【问题标题】:Abstract classes and methods in C#C# 中的抽象类和方法
【发布时间】:2012-01-20 19:02:04
【问题描述】:

我想为所有参数类型的类创建一个抽象基类,以便在我的应用程序中继承。所有参数都将具有名称、ID 和必需的属性。

所有参数都将通过 SetProperties 方法从 XML 设置其属性(下面显示的 XmlParser 类仅用于演示)。

由于所有参数都将具有相同的 3 个属性,因此我希望基类设置这些属性,但让继承类扩展 SetProperties 方法以设置它包含的其他属性。

我正在考虑诸如覆盖 Control 上的事件之类的事情。

这是我的想法的一个示例,虽然它不起作用。

abstract class ParameterBase
{
    protected string ParameterName;
    protected bool IsRequired;
    protected int ParameterId;

    public abstract void SetProperties(string xml)
    {
        this.ParameterName = XmlParser.GetParameterName(xml);
        this.IsRequired = XmlParser.GetIsRequired(xml);
        this.ParameterId = XmlParser.GetParameterId(xml);
    }
}

abstract class Parameter1 : ParameterBase
{
    private string _value;

    public string ParameterName
    {
        get { return base.ParameterName; }
    }

    public bool IsRequired
    {
        get { return base.IsRequired; }
    }

    public int ParameterId
    {
        get { return base.ParameterId; }
    }

    public string Value
    {
        get { return _value; }
    }

    public Parameter1()
    {

    }

    public override void SetProperties(string xml)
    {
        base.SetProperties(xml);

        _value = XmlParser.GetValue(xml);
    }
}

【问题讨论】:

  • 请定义“它不起作用。”你有例外吗?出乎意料的结果?
  • 对不起 - 它甚至不会编译 - 你不能调用抽象基成员:base.SetProperties(xml);来自子类

标签: c# inheritance abstract-class


【解决方案1】:

我会这样做,就像这样:

abstract class ParameterBase
{
    protected string ParameterName;
    protected bool IsRequired;
    protected int ParameterId;

    public abstract void SetProperties(string xml);

}

并派生出一个:

public  class Parameter1 : ParameterBase 
{
    public override void SetProperties(string sml)
    {
       //set properties including those ones of parent
    }
}

以这种方式管理起来更容易、更清晰。在单独的基类中移动公共属性很好,但持久性管理(保存/加载)留给孩子。 他们应该知道怎么做。

提供的代码有几个问题:

  • abstract 方法不能有主体

  • 你有奇怪的public override void SetValues(string xml),我认为应该是
    public override void SetProperties(string xml)

【讨论】:

  • 如果我所有的子类共享相同的 3 个属性,为什么不让基类处理设置这些属性的值呢?因为值是从 XML 设置的,所以我不想公开子类的任何设置器,所以修改值的唯一方法是通过 SetProperties 方法。
  • 如果要这样管理,不要像abstract那样声明类,而是像virtual方法SetProperties这样的简单基类。在这种情况下,您可以在基类函数中声明一个主体,以便在其子级之间共享属性,以及函数。
  • @Tigran 纠正我,如果我在你的抽象类上错了,它不违反 SOILD 原则,但如果你用虚拟体实现它是否违反了固体原则。请清除我。
  • @PEO:它是一个简单的继承。我不确定您在哪里看到违反 SOLID 的情况。我只是在基类中使用abstract 来强制客户端(实现它的人)用其具体实现覆盖该函数。
【解决方案2】:

我可以看到您的代码存在四个问题:

  1. 您正在重新定义 3 个共享属性,并尝试将它们命名为与现有字段相同的名称。这是不允许的。最简单的方法是在基类中实现属性,就像在继承类中实现 Value 一样:使用支持字段。在 C# 3.0 及更高版本(Visual Studio 2008 及更高版本)中,您可以将自动实现的属性与私有设置器一起使用。这将使编译器为您创建支持字段。例如:

    公共字符串 ParameterName { get;私人套装; }
  2. 您将SetProperties 方法声明为abstract。这应该是virtualabstract 表示子类必须定义整个实现。这里不是这样。

  3. 在您的派生类中,您覆盖了SetValues,但该方法称为SetProperties

  4. 您将Parameter1 声明为抽象。您不能实例化抽象类,因此您还必须从 Parameter1 继承一个类才能使用它。我猜你只想删除 abstract 限定符。

【讨论】:

  • Argh - 这么多错误:p。我肯定在考虑虚拟方法,而不是抽象的。
【解决方案3】:

我会用受保护的设置器将公共基类属性设为公共,然后您可以从任何派生类访问它们,无需重复代码!

protected string ParameterName { get; protected set; }; 
protected bool IsRequired  { get; protected set; }; 
protected int ParameterId  { get; protected set; };

【讨论】:

    【解决方案4】:

    你把它弄得太复杂了。前三个属性可以从基类继承:

    public abstract class ParameterBase 
    { 
        public string ParameterName { get; private set; }
        public bool IsRequired { get; private set; }
        public int ParameterId { get; private set; }
    
        public virtual void SetProperties(string xml) 
        { 
            ParameterName = XmlParser.GetParameterName(xml); 
            IsRequired = XmlParser.GetIsRequired(xml); 
            ParameterId = XmlParser.GetParameterId(xml); 
        } 
    } 
    
    public class Parameter1 : ParameterBase 
    { 
        public string Value { get; private set; }
    
        public override void SetProperties(string xml)
        {
            base.SetProperties(xml);
            Value = XmlParser.GetValue(xml);
        }
    } 
    

    另请注意,抽象方法不能有主体,而是以分号结尾:

    public abstract void SetProperties(string xml);
    

    如果你想给它一个基本的实现,你必须把它声明为虚拟的。

    (并且您必须覆盖SetProperties,而不是SetValue。)

    【讨论】:

    • 不可能在抽象方法中声明主体,如SetProperties
    • 是的,我把它改成了虚拟的。
    【解决方案5】:

    如前所述,不要想太多。我将声明抽象参数类,使其具有一个构造函数(受保护),该构造函数采用必需的三个属性(Name、IsRequired 和 ID)。这意味着每个具体的子类型必须正确地构造它。

    然后,我将有一个抽象工厂方法CreateInstance(),每个具体子类型都必须实现它,并返回一个 AbstractParameter 实例。为什么?阅读Liskov Substitution Principle。当然,在现实世界中,将如何创建参数实例的关注点与 存在 的关注点分开可能更有意义,而不是使用 工厂方法一个参数,通过将构造逻辑移动到它自己的工厂类 (AbstractParameterFactory?)。

    不过,我可能会注意到,您缺少所有参数都将具有的基本属性:值。您可以考虑将抽象参数的基类设为泛型。

    无论如何,这是我的AbstractParameter 课程:

    public abstract class AbstractParameter
    {
        public string Name       { get ; protected set ; }
        public bool   IsRequired { get ; protected set ; }
        public int    ID         { get ; protected set ; }
    
        protected AbstractParameter( string name , bool isRequired , int id )
        {
            this.Name       = name;
            this.IsRequired = isRequired;
            this.ID         = id;
            this.Value      = default(T) ;
            return;
        }
    
        public abstract AbstractParameter CreateInstance( string xml ) ;
    
    }
    

    派生自AbstractParameter 的具体参数类可能看起来像这样:

    public class ConcreteParameter : AbstractParameter
    {
        public ConcreteParameter( string name , bool isRequired , int id ) : base( name , isRequired , id )
        {
            return ;
        }
    
        public override AbstractParameter CreateInstance( string xml )
        {
            string            name     = XmlParser.GetName();
            bool              required = XmlParser.GetIsRequired();
            int               id       = XmlParser.GetID();
            ConcreteParameter instance = new ConcreteParameter( name , required , id );
    
            return instance;
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-14
      • 1970-01-01
      • 2012-10-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-28
      • 2021-04-14
      • 1970-01-01
      相关资源
      最近更新 更多