抽象还是不抽象
预先感谢您阅读本文。我不完全理解如何/何时使用摘要,所以我试图思考我从事的每个项目,看看有一天它是否会全部点击微笑 | :)
另外,可访问级别(私有、受保护、内部)与关键字 static、abstract 和 override 的混合往往会让我有点困惑。我如何定义这个方法/属性/类......
这对我来说并不是一个大谜团,但有些项目让我在处理这些主题时进行编码。
话虽如此,
我有一个读取 XML 文档并输出文本和图像文件的应用程序。我还将所有信息存储在数据库中。我让它工作得很好。
XML 具有包含必填字段的标准实现,并且被多个组织用来向我的应用程序提交数据。所有组织都应该(至少)使用 XML 实施指南中概述的所需节点/元素。
因此,我希望有一个默认的数据对象类型,以便能够为所需元素派生特定组织的数据类型。 (如果要使用该对象,则必须实现这些字段)。
如果组织。只要使用默认的要求,我就可以使用默认的对象。如果他们使用附加(可选)字段,我将必须创建一个继承默认类型的新类型。
我的第一个想法是使用具有受保护属性的抽象类来满足我的最低要求:
public abstract partial class AbstractDataObject
{
protected string DataObjectName;
protected DateTime? DataObjectDate;
etc...
}
然后,如果组织只使用节点的必需元素而没有可选元素,我可以使用“默认”对象。
internal partial class DefaultDataObject : AbstractDataObject
{
public new string DataObjectName { get; set; }
public new DateTime? DataObjectDate { get; set; }
etc...
}
但是,如果组织使用所需节点的可选字段,我可以使用派生的组织数据对象。
internal sealed partial class OranizationDataObject : AbstractDataObject
{
public new string DataObjectName { get; set; }
public new DateTime? DataObjectDate { get; set; }
etc...
//Optional fields used by this organization
public string DataObjectCode { get; set; }
etc...
}
我需要抽象类吗?在我看来,我可以只拥有一个 DefaultDataObject (类似的东西):
internal partial class DefaultDataObject
{
public virtual string DataObjectName { get; set; }
public virtual DateTime? DataObjectDate { get; set; }
etc...
}
然后:
internal sealed partial class OranizationDataObject : DefaultDataObject
{
public override string DataObjectName { get; set; }
public override DateTime? DataObjectDate { get; set; }
etc...
//Optional fields used by this organization
public string DataObjectCode { get; set; }
etc...
}
我只是真的想了解如何定义这些对象,以便我可以在每个组织中重用它们。两种方法似乎都有效,但我希望了解如何正确定义它们。
将 XML 放入上述对象中:
public DefaultDataObject ExtractXmlData(XContainer root)
{
var myObject = (from t in root.
Elements("ElementA").Elements("ElementB")
select new DefaultDataObject()
{
DataObjectName = (String)t.Element("ChildElement1"),
DataObjectDate =
Program.TryParseDateTime((String)
t.Elements("ChildElement2")
.ElementAtOrDefault(0)
),
etc....
OR
public OranizationDataObject ExtractXmlData(XContainer root)
{
var myObject = (from t in root.
Elements("ElementA").Elements("ElementB")
select new OranizationDataObject()
{
DataObjectName = (String)t.Element("ChildElement1"),
DataObjectDate = Program.TryParseDateTime(
(String)t.Elements("ChildElement2")
.ElementAtOrDefault(0)),
DataObjectCode = (String)t.Element("ChildElement3"),
等...
再次感谢您的阅读。别忘了给服务员小费……
乔
thanks in advance for reading this. I don’t fully understand how/when to use abstracts so I am trying to think about it each project I work on to see if it will all click some day Smile | :)
Also, the mix of accessibility levels (private, protected, internal) with keywords static, abstract, and override tend to leave me a little confused. How do I define this method/property/class....
It's not all a big mystery to me but some projects have me coding in circles when dealing with these topics.
With that said,
I have an application that reads an XML document and outputs text and image files. I’m also storing all of the information in a database. I have it working nicely.
The XML has a standard implementation with required fields and is used by multiple organizations to submit data to my app. All organizations should use (at least) the required nodes/elements that are outlined in the XML implementation guide.
So, I want to have a default data object type to be able to derive a specific organization’s data type for required elements. (If this object is going to be used, these are the fields that must be implemented).
If the org. just uses the default requirements, I can use the default object. If they use additional (optional) fields, I’ll have to create a new type inheriting the default type.
My first thought was to use and abstract class that had protected properties for my bare minimum requirements:
public abstract partial class AbstractDataObject
{
protected string DataObjectName;
protected DateTime? DataObjectDate;
etc...
}
Then, if the organization just uses the required elements of the node and no optional elements, I can use a “default” object.
internal partial class DefaultDataObject : AbstractDataObject
{
public new string DataObjectName { get; set; }
public new DateTime? DataObjectDate { get; set; }
etc...
}
But, if an organization uses optional fields of the required node, I can use a derived organization data object.
internal sealed partial class OranizationDataObject : AbstractDataObject
{
public new string DataObjectName { get; set; }
public new DateTime? DataObjectDate { get; set; }
etc...
//Optional fields used by this organization
public string DataObjectCode { get; set; }
etc...
}
Do I need the abstract class? It seems to me I can just have a DefaultDataObject (something like):
internal partial class DefaultDataObject
{
public virtual string DataObjectName { get; set; }
public virtual DateTime? DataObjectDate { get; set; }
etc...
}
And then:
internal sealed partial class OranizationDataObject : DefaultDataObject
{
public override string DataObjectName { get; set; }
public override DateTime? DataObjectDate { get; set; }
etc...
//Optional fields used by this organization
public string DataObjectCode { get; set; }
etc...
}
I’m just really trying to understand how to define these objects so I can reuse them per organization. Both ways seem to work, but I am hoping to understand how to define them properly.
Getting the XML into above objects:
public DefaultDataObject ExtractXmlData(XContainer root)
{
var myObject = (from t in root.
Elements("ElementA").Elements("ElementB")
select new DefaultDataObject()
{
DataObjectName = (String)t.Element("ChildElement1"),
DataObjectDate =
Program.TryParseDateTime((String)
t.Elements("ChildElement2")
.ElementAtOrDefault(0)
),
etc....
OR
public OranizationDataObject ExtractXmlData(XContainer root)
{
var myObject = (from t in root.
Elements("ElementA").Elements("ElementB")
select new OranizationDataObject()
{
DataObjectName = (String)t.Element("ChildElement1"),
DataObjectDate = Program.TryParseDateTime(
(String)t.Elements("ChildElement2")
.ElementAtOrDefault(0)),
DataObjectCode = (String)t.Element("ChildElement3"),
etc....
Again, thanks for reading. Don't forget to tip your wait staff....
Joe
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
首先,如果您的基类是普通的 DTO 类,则它不需要是抽象的。如果您没有任何需要由派生类以不同方式实现的功能,则只需将其设置为一个普通基类,它将包含通用属性。
接下来,如果您要 隐藏它们(使用
new
关键字)。您的第一个DefaultDataObject
代码片段不必要地创建了一堆具有相同名称的新属性。完全删除它们 - 它们已经在基类中定义。[编辑]我最初没有注意到这一点,@svick 警告我,你的基类实际上包含字段而不是属性,这让我想知道为什么您根本需要添加
new
关键字。我快速浏览了你的代码并将它们视为属性。在任何情况下,您都不应该公开公共字段 - 至少通过添加{ get; 将它们更改为自动实现的属性。放; }
块。换句话说,这很简单:
作为旁注,但无论如何重要的恕我直言,您应该简化命名(并使其更清楚您的代码的作用)。例如,无需在每个属性名称中重复“DataObject”。但由于您的代码可能只是一个简化版本,所以这并不重要。
最后,您听说过
XmlSerializer
?您不需要手动遍历 XML 元素。调用XmlSerializer
来序列化和反序列化数据就足够了。First of all, your base class doesn't need to be abstract if it's a plain DTO class. If you don't have any functionality that needs to be implemented differently by derived classes, you can simply make it a plain base class which will hold common properties.
Next, there is no point in declaring properties in the base class (abstract in your case), if you are going to hide them (using the
new
keyword). You first code snippet ofDefaultDataObject
unnecessarily creates a bunch of new properties with the same name. Remove them completely - they are already defined in the base class.[Edit] I didn't notice this initially, and @svick warned me, that your base class actually contained fields instead of properties, which makes me wonder why you needed to add the
new
keyword at all. I went over your code quickly and saw them as properties. In any case, you should never expose public fields - at least change them to auto-implemented properties by adding the{ get; set; }
block.In other words, this would simply work:
As a side note, but nevertheless important IMHO, you should simplify naming (and make it more clearer what your code does). There is no need to repeat "DataObject" in every property name, for example. But since your code is probably only a simplified version, it doesn't matter.
Lastly, have you heard of
XmlSerializer
? You don't need to traverse the XML elements manually. It is enough to callXmlSerializer
to both serialize and deserialize your data.我需要知道的一切都是我从芝麻街学到的
仔细检查您的类设计,以确保您已识别出所有相同和不同的内容。可以这么说,与您的班级一起玩电脑,看看他们如何做相同、不同或相同但方式不同的事情。
什么是相同、不同、相同但不同可能会随着您玩电脑而改变。
一般性地思考 OO 类的两大支柱。多态与继承
正如你所做的那样。就 C# 实现本身而言,没有那么多。
事物如何聚集成相同与不同将有助于推动实施
这都是相对的。
虚拟
方法。代表
。实施建议
将方法和字段设置为默认
受保护
。Private
不会被继承。设计发生变化,保持灵活性。如果某些东西必须是私有的,那没问题。虚拟
意味着您可以更改子类中的实现。这并不意味着您必须这样做。人们似乎没有充分利用
委托
。它们非常适合多态方法。公共字段没有任何问题。公共
字段
和公共自动实现属性
之间的实际区别是什么?没有什么。它们都直接返回(或设置)基础值。那么,为财产而烦恼又有什么意义呢?如果您想公开揭示与“自然”状态不同的潜在价值。例如,返回特定格式的数字。当然,同一个字段可以有不同的属性。属性
可以有get
,但没有set
。或者反之亦然。 get 和 set 也可以有不同的访问级别。通常,您会将其视为公共 get 和受保护(或私有)集。Everything I need to know I learned from Sesame Street
Scrub your class design hard to make sure you've identified everything that is the same and different. Play computer, so to speak, with your classes and see how they do the same, different, or the same thing but in different ways.
What is the same, different, same but differently will likely change as you play computer.
Think in general terms of the two pillars of OO Classes. Polymorphism and Inheritance
As you do the above that is. Not so much in terms of C# implementation per se.
How things clump into same vs. different will help drive implementation
And it's all relative.
abstract
class instead of concrete base class.virtual
method.delegate
perhaps.Implementation Suggestions
Make methods and fields
protected
as a default.Private
does not get inherited. Designs change, stay flexible. If something just has to be private, fine.virtual
means you can change implementation in a sub class. It does not mean you must.Folks seem to under-utilize
delegate
s. They're super for polymorphic methods.There is nothing wrong with public fields. What's the practical difference between a public
field
and a public auto-implementedproperty
? Nothing. They both directly return (or set) the underlying value. So what's the point of even bothering with properties? If you want to publicly expose an underlying value differently than it's "natural" state. For example, returning a number in a specific format. And of course you can have different properties for the same field.A
Property
can have aget
without aset
. Or vice versa. Also get and set can have different access levels. Often you'll see this as a public get and a protected (or private) set.这取决于派生类型想要做什么。如果他们打算使用默认实现并仅以某种方式对其进行扩展,那么将默认类作为非抽象基类就可以了。
另一方面,如果他们最有可能重新实现功能,您应该有一个抽象基类(或接口)和一个单独的默认类。
如果您由于某种原因不知道它是哪一个,您可以通过使用抽象基类并保留默认类未密封的方式让继承者进行选择。
另外,看看你的代码,你似乎误解了各种关键字的作用。大多数时候,您不想像这样使用
new
。它的作用是定义另一个具有相同名称的成员,与原始成员无关。此外,如果您不想更改某些内容,就没有理由覆盖
它。因此,如果您希望派生类不必重新实现这些属性,则根本不必将它们设为虚拟的。It depends on what the derived types will want to do. If they are going to use the default implementation and only expand on it somehow, then having the default class as the non-abstract base class is fine.
On the other hand, if they are most likely going to re-implement the functionality, you should have an abstract base class (or an interface) and a separate default class.
If you for some reason don't know which one is it, you can let the inheritors choose by having an abstract base class and leaving the default class unsealed.
Also, looking at your code, it seems you misunderstand what the various keywords do. Most of the time, you do not want to use
new
like this. What it does is to define another member with the same name, unrelated to the original one. Also, there's no reason tooverride
something if you don't want to change it. So, if you expect that the derived classes won't have to reimplement the properties, you don't have to make themvirtual
at all.抽象类已经可以实现可以继承的东西
具体类可以添加新的属性和方法
属性
DataObjectName
和DataObjectDate
在新类中已经可用,因为它们是自动从基类继承。但是,如果抽象类定义了抽象成员,则必须在派生类中实现它。
假设基类定义了
派生类必须这样做,
如果您的基类没有抽象成员,则它不需要是抽象的,可以直接发挥默认数据对象的作用。
这里不需要关键字“partial”。仅当您想将一个类拆分为多个文件中的多个部分时,它才有用。
这里关键字
new
是错误的。它用于隐藏继承的成员。这意味着继承的成员将隐藏在新声明的“后面”。你需要的是覆盖。这不会隐藏成员,而是在派生类中提供同一成员的替代实现。An abstract class can already implement things that can be inherited
A concrete class can add new properties and methods
The properties
DataObjectName
andDataObjectDate
are already available in the new class, because they are automatically inherited from the base class.If the abstract class defined an abstract member, however, you would have to implement it in the derived class.
Say the base class defines
The the derived class has to do this
If your base class does not have abstract members, it does not need to be abstract and can play the role of your default data object directly.
The keyword 'partial` is not needed here. It is only useful if you want to split one class into several pieces over several files.
The keyword
new
is wrong here. It is used to shadow an inherited member. This means that the inherited member will be hidden "behind" the new declaration. What you need, is to override. This does not hide a member, but provide an alternative implementation of the same member in the derived class.