繁体   English   中英

C#和多态

[英]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图表构造函数,为此,我当然extendChartHelper类:

        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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM