抽象,或不抽象

时间:2012-01-14 21:56:31

标签: c# abstract-class

提前感谢您阅读本文。我不完全理解如何/何时使用摘要,所以我试着想一下我工作的每一个项目,看看有一天它是否会全部点击:)

此外,可访问性级别(私有,受保护,内部)与关键字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"),

等...

再次感谢阅读。不要忘记给你的侍应生小费....

4 个答案:

答案 0 :(得分:4)

  1. 首先,如果基类是普通的DTO类,则不需要是抽象的。如果您没有任何需要通过派生类以不同方式实现的功能,则可以简单地将其设置为包含公共属性的普通基类。

  2. 接下来,如果您要hide them(使用new关键字),则在基类中声明属性(在您的情况下为摘要)是没有意义的。您首先在DefaultDataObject的代码片段中不必要地创建了一堆具有相同名称的新属性。完全删除它们 - 它们在基类中已经已定义

    [编辑] 我最初没有注意到这一点,@ svick警告我,您的基类实际上包含字段而不是属性,这让我想知道为什么您需要添加new关键字。我快速浏览了你的代码并将它们视为属性。在任何情况下,您都不应该公开公共字段 - 至少通过添加{ get; set; }块将它们更改为自动实现的属性。

    换句话说,这只会起作用:

    // this doesn't need to be abstract.
    // just put all the common stuff inside.
    public class BaseDO
    {
        // as svick pointed out, these should also be properties.
        // you should *never* expose public fields in your classes.
    
        public string Name { get; set; }
        public DateTime? Date { get; set; }
    }
    
    // don't use the new keyword to hide stuff.
    // in most cases, you won't need that's behavior
    public class DerivedDO : BaseDO
    {
        // no need to repeat those properties from above,
        // only add **different ones**
        public string Code { get; set; }
    }
    
  3. 作为旁注,但重要的恕我直言,你应该简化命名(并使其more clearer代码所做的事情)。例如,不需要在每个属性名称中重复“DataObject”。但由于您的代码可能只是简化版本,因此无关紧要。

  4. 最后,你听说过XmlSerializer吗?您不需要手动遍历XML元素。只需致电XmlSerializer即可对您的数据进行序列化和反序列化。

答案 1 :(得分:3)

我需要知道的一切我从芝麻街学到的东西
努力磨砂你的班级设计,以确保你已经识别出相同不同的所有内容。可以说,与您的课程一起玩电脑,看看他们是如何做同样的,不同的,或者以不同的方式做同样的事情。

什么是相同不同相同但不同可能会随着您玩电脑而改变。

一般性地考虑OO类的两个支柱。多态与遗传
正如你所做的那样。与C#实现本身无关。

如何将相同与不同的结合起来将有助于推动实施
这都是相对的。

  • 更多相同的默认行为?也许是一个具体的基类而不是抽象的。
  • 更多同样的事情,但不同?也许是abstract类而不是具体的基类。
  • 执行 x 的默认方式?也许是virtual方法。
  • 每个人都做同样的事情,但没有两个同样的方式?也许是delegate

实施建议

  • 将方法和字段protected设为默认值。 Private不会继承。设计变化,保持灵活性。如果必须私有,那就好了。

  • virtual表示您可以更改子类中的实现。这并不意味着你必须。

  • 人们似乎未充分利用delegate。他们对多态方法非常有用。

  • 公共领域没有任何问题。公共field与公开自动实施的property之间的实用区别是什么?没有。它们都直接返回(或设置)基础值。那么甚至打扰财产有什么意义呢?如果您希望以不同于“自然”状态的方式公开公开基础价值。例如,以特定格式返回数字。当然,您可以为同一个字段设置不同的属性。

  • Property可以有get而没有set。或相反亦然。获取和设置也可以具有不同的访问级别。通常,您会将此视为公共获取和受保护(或私有)设置。

答案 2 :(得分:2)

这取决于派生类型想要做什么。如果他们要使用默认实现并且只是以某种方式展开它,那么将默认类作为非抽象基类就可以了。

另一方面,如果他们最有可能重新实现该功能,则应该有一个抽象基类(或接口)和一个单独的默认类。

如果由于某种原因你不知道它是哪一个,你可以让继承者选择一个抽象的基类并保持默认的类是未密封的。

此外,查看您的代码,您似乎误解了各种关键字的作用。大多数情况下,想要像这样使用new。它的作用是定义具有相同名称的另一个成员,与原始成员无关。此外,如果您不想更改它,则没有理由override。因此,如果您希望派生类不必重新实现属性,则根本不必使它们virtual

答案 3 :(得分:1)

抽象类已经可以实现可以继承的东西

public abstract class DataObjectBase
{
    public string DataObjectName { get; set; }
    public DateTime? DataObjectDate { get; set; }
}

具体类可以添加新属性和方法

public class DerivedDataObject : DataObjectBase 
{
    public int NewProperty { get; set; }
}

属性DataObjectNameDataObjectDate已在新类中可用,因为它们会自动从基类继承。

但是,如果抽象类定义了一个抽象成员,则必须在派生类中实现它。

假设基类定义

public abstract void SomeMethod(string name);

派生类必须这样做

public override void SomeMethod(string name)
{
    ...
}

如果您的基类没有抽象成员,则它不需要是抽象的,可以直接扮演默认数据对象的角色。


此处不需要关键字'partial`。只有当您想将一个类分成几个文件中的几个部分时才有用。

关键字new在这里是错误的。它用于遮蔽继承的成员。这意味着继承的成员将隐藏在新声明的“后面”。你需要的是覆盖。这不会隐藏成员,而是在派生类中提供相同成员的替代实现。