C#中的抽象类和方法
本文关键字:方法 抽象类 | 更新日期: 2023-09-27 18:20:59
我想为应用程序中的所有参数类型类创建一个抽象基类来继承。所有参数都将具有名称、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);
}
}
我会简单地这样做:
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个共享属性,并试图将它们命名为与现有字段相同的名称。这是不允许的。最简单的方法是在基类中实现属性,方法与在继承类中实现
Value
的方法相同:使用backing字段。在C#3.0及以上版本(Visual Studio 2008及更高版本)中,您可以将自动实现的属性与专用setter一起使用。这将使编译器为您创建支持字段。例如:公共字符串ParameterName{get;private set;}
-
您正在将
SetProperties
方法声明为abstract
。这应该是virtual
。abstract
意味着子类必须定义整个实现。这里的情况并非如此。 -
在派生类中,可以重写
SetValues
,但该方法称为SetProperties
。 -
您正在将
Parameter1
声明为抽象。你不能实例化抽象类,所以你必须从Parameter1
继承一个类才能使用它。我猜你只想删除abstract
限定符。
我会使用受保护的setter将公共基类属性设置为Public,然后您可以从任何派生类访问它们,而无需重复代码!
protected string ParameterName { get; protected set; };
protected bool IsRequired { get; protected set; };
protected int ParameterId { get; protected set; };
你把它搞得太复杂了。前三个属性可以从基类中继承:
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
。)
如前所述,不要想太多。我会声明抽象参数类,这样它就有一个单独的构造函数(受保护),它接受三个强制性属性(Name、IsRequired和ID)。这意味着每个混凝土子类型都必须正确构造它。
然后,我会有一个抽象的工厂方法,CreateInstance()
,每个具体的子类型都必须实现,返回AbstractParameter的一个实例。为什么?阅读利斯科夫替代原则。当然,在现实世界中,通过将构造逻辑移动到其自己的工厂类(AbstractParameterFactory
?)中,将如何创建参数实例的问题与作为参数的问题分离开来,而不是使用出厂方法,可能会更有意义。
不过,我可能会注意到,您缺少一个所有参数都具有的基本属性:Value。您可以考虑将抽象参数的基类设为泛型。
总之,这是我的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;
}
}