繁体   English   中英

返回清单 <interface> 在C#中

[英]returning a list<interface> in C#

在有关使用IEnumerable而不是List的初步建议之后进行了编辑。

我正在尝试这样做:

public interface IKPIDetails // Previously: interface IKPIDetails
{ 
    string name {get; set;}
    //...
}


public abstract class BaseReport
{
    public List<IKPIDetails> m_KPIDetails;  // Previously: list<IKPIDetails> m_KPIDetails;

    public BaseReport()
    {
        m_KPIDetails = MakeReportDataStructure();
        //...
    }
    public abstract List<IKPIDetails> MakeReportDataStructure(); // Previously: public abstract IKPIDetails MakeReportDataStructure();

    //...
}


public class AirTemp_KPIDetails : NetVisSolution.Reports.IKPIDetails // Previously: protected class AirTemp_KPIDetails : IKPIDetails
{
    #region IKPIDetails implementation
    private string _Name;
    public string Name
    {
        get { return _Name; }
        set { _Name = value; }
    }
    #endregion
    ...
}

public class SSAirTempSummaryReport : BaseReport
{
    public SSAirTempSummaryReport() : base ()
    {
        // Do any extra initialisation here
        m_reportName = "Air Temperature Summary Report";
    }

    //It now complains on the declaration below at the word
    // MakeReportDataStructure()
    public override IEnumerable<IKPIDetails> MakeReportDataStructure() // Previously: public override List<IKPIDetails> MakeReportDataStructure()
    {
        List<AirTemp_KPIDetails> d = new List<AirTemp_KPIDetails>();
        return  d;  // <-- this is where it used to break
    }

    //...
}

因此,我有一个报表数据对象接口,并可能有多个报表数据类实现此接口并添加其特定的额外位。 我有一个抽象的报告类,实现了通用的报告功能,并且有多个派生类,每个派生类都使用自己的报告数据类。

不幸的是,当我尝试在派生类中创建报表详细信息结构的列表并将其作为接口列表传递回基类时,它抱怨:

Cannot implicitly convert type 
'System.Collections.Generic.List<NetVisSolution.Reports.AirTemp_KPIDetails>' to 
'System.Collections.Generic.List<NetVisSolution.Reports.IKPIDetails>'

它不会让我隐式或显式地执行此操作。 有什么办法可以做到这一点?

提前致谢,

---阿利斯泰尔。

public override List<IKPIDetails> MakeReportDataStructure()
{
    List<AirTemp_KPIDetails> d = new List<AirTemp_KPIDetails>();
    return  d;  // <-- this is where is breaks
}

应该:

public override List<IKPIDetails> MakeReportDataStructure()
{
    List<IKPIDetails> d = new List<AirTemp_KPIDetails>();
    return  d;
}

您的分配不起作用,因为在List<T> ,类型参数T不是协变的,也就是说,当T更具体时,不允许分配。 如果您使用IEnumerable ,您的代码将正常工作:

public override IEnumerable<IKPIDetails> MakeReportDataStructure()
{
    List<AirTemp_KPIDetails> d = new List<AirTemp_KPIDetails>();
    return  d;  // <-- works, because T in IEnumerable is covariant
}

您可能会问,为什么IEnumerable是协变的? 嗯, IEnumerable只允许您读取数据(因此协方差用<out T>标记),并且您不能向其中写入任何对象。 List允许您将对象写到集合中,并且会遇到危险,后来您会向该集合中写入不太具体的类型,这可能会导致错误,因为不太具体的类型不能提供与更多派生类型相同的功能:

public override IEnumerable<BaseClass> MakeList()
{
    List<DerivedClass> d = new List<DerivedClass>();
    // ...
    return  d; // assume it would work
}

var l = MakeList();
l.Add(BaseClass); // now we added object of BaseClass to the list that expects object of DerivedClass, any operation on the original list (the one with List<DerivedClass> type could break

这两个列表是不同的,即使AirTemp_KPIDetailsIKPIDetails (即具有is-a -relation关系)也是如此。 您必须将元素从一个列表复制到另一个列表:

kpiDetailsList = new List<IKPIDetails>(airTempKPIList);

总的来说,这属于同方差和相反方差的主题。 您可能需要阅读Wiki上有关协方差和相反方差的文章(计算机科学)

您不应该将一种类型的列表转换为另一种类型,因为插入操作将失败或获取。

示例:类型A实现(扩展)类型B

List<A> listA;
List<B> listB;


((List<B>) listA).add(new B()); 

如果这是合法的,则可以通过放置比A更通用的内容来破坏listA不变式。

A a = ((List<A>) listB).get(); //like get first, or something similar

这将打破只有A对象可以分配给A引用的事实。

您必须将列表创建为接口列表,而不是派生类型:

List<IKPIDetails> d = new List<IKPIDetails>();

尝试使用下面的代码。

public override List<IKPIDetails> MakeReportDataStructure() 
{ 
    return new List<AirTemp_KPIDetails>() as List<IKPIDetails>; 
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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