[英]C# and Polymorphism
我正在尝试学习C#,并且直到现在为止对Java都有很多帮助。
现在我已经有好几次遇到这个问题了,它开始让我有些烦恼,因此为了举例,让我们看一些代码。
例如,我有以下abstract
类:
public abstract class ChartHelper
{
public System.Windows.Forms.DataVisualization.Charting.Chart resultChart { get; set; }
public String TimeType { get; set; }
protected List<IObject> _datalist;
protected TimeType _timeType;
protected DateTime _stopDate;
protected DateTime _startDate;
}
现在,您可以看到我有一个List<>
,它将包含接口IObject
元素:
public interface IObject
{
DateTime GetPeriod();
}
现在,实现此接口的元素可能如下:
public class Email : IObject
{
public virtual DateTime PERIOD { get; set; }
public virtual int email_u_kam { get; set; }
public virtual int kam_ialt { get; set; }
public virtual int ms_besvarelses_pc { get; set; }
public virtual int total_besvarelses_pc { get; set; }
public DateTime GetPeriod()
{
return PERIOD;
}
}
现在,为了扩展ChartHelper
类,我想创建一个Email
图表构造函数,为此,我当然extend
了ChartHelper
类:
public class EmailChartGenerator : ChartHelper, IChart
{
public EmailChartGenerator(List<Email> dataList, TimeType timeType, DateTime startDate, DateTime stopDate) : base()
{
_startDate = startDate;
_stopDate = stopDate;
_datalist = dataList;
_timeType = timeType;
}
}
请注意,在构造函数中,我将列表指定为Email
类型,因为此生成器仅用于创建显示Email
数据的图表。
现在到问题了。 因为抽象类ChartHelper
_datalist的protected
字段被指定为IObject
所以在生成器的构造函数中出现以下错误:
Cannot implicitly convert type 'System.Collections.Generic.List<Henvendelser.Objects.Email>' to 'System.Collections.Generic.List<Henvendelser.Objects.IObject>'
即使Email
对象正在实现IObject
接口。 我知道这是一篇很长的文章,但是我需要确保我拥有所有细节! 为什么会发生这种情况,并且Email
不应该等于IObject
?
不, Email
不应等于IObject
。 因此, List<Email>
不是List<IObject>
因为List<T>
具有Add(T)
方法,因此集合不能协变。 例如,最初的List<Email>
转换为List<IObject>
,其Add(T)
方法将变为Add(IObject)
并允许任何IObject
进入,而不一定是Email
。 因此,您可以从List<Email>
获得一个看起来完全不相关的对象。
另一方面,可以将IEnumerable<Email>
分配给IEnumerable<IObject>
,因为IEnumerable<T>
提供了只读接口,因此可以(并且是) 协变的 。
如果要在List<A>
和List<B>
之间转换(并且两者之间存在合法转换),请使用Cast<T>()
方法 。
您所面临的问题与协方差和协方差有关 。 通常,这意味着通用类型参数只能在特殊情况下隐式转换为某些通用化或专业化。
您可以从两个方面解决这个问题:在运行时显式转换类型或简化设计。
第一种方法更易于应用,但是由于您是在运行时解决问题的,因此它可能不是您所用的最佳解决方案。
public EmailChartGenerator(List<Email> dataList, TimeType timeType, DateTime startDate, DateTime stopDate) : base()
{
_startDate = startDate;
_stopDate = stopDate;
_datalist = dataList.ConvertAll(e => (IObject)e);
_timeType = timeType;
}
有关更多信息, 请在此处阅读 。
第二种方法是确定基础集合的性质。 如果您只想收集集合中的一些数据并从随机集合中对其进行初始化,请使用IEnumerable
:
public abstract class ChartHelper
{
protected IEnumerable<IObject> _datalist;
public ChartHelper()
{
_datalist = new List<IObject>();
}
public ChartHelper(IEnumerable<IObject> data)
{
_datalist = data;
}
}
由于IEnumerable
是协变的,因此可以像下面这样实现构造函数:
public EmailChartGenerator(List<Email> dataList, TimeType timeType, DateTime startDate, DateTime stopDate)
: base(dataList)
{
_startDate = startDate;
_stopDate = stopDate;
_timeType = timeType;
}
但是,您也可以轻松地在基类中维护一个列表,并从您的集合中对其进行初始化:
public abstract class ChartHelper
{
protected List<IObject> _datalist;
public ChartHelper()
{
_datalist = new List<IObject>();
}
public ChartHelper(IEnumerable<IObject> data)
{
_datalist = new List<IObject>(data);
}
}
当然,您可以进一步改进此设计,但总的来说,它应该可以完全满足您的要求。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.