1

在关于使用 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>'

它不会让我隐含或明确地做到这一点。有什么办法可以做到这一点吗?

提前致谢,

--- 阿利斯泰尔。

4

5 回答 5

4
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
于 2012-09-18T11:44:32.493 回答
1

这两个列表是不同的,即使AirTemp_KPIDetails我是一个IKPIDetails(即有一个is-a关系)。您必须将元素从一个列表复制到另一个:

kpiDetailsList = new List<IKPIDetails>(airTempKPIList);

一般来说,这属于协方差和反方差的主题。您可能想阅读关于协变和逆变(计算机科学)的 Wiki 文章。

于 2012-09-18T11:45:21.030 回答
1

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

示例:类型 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 引用的事实。

于 2012-09-18T11:49:04.323 回答
0

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

List<IKPIDetails> d = new List<IKPIDetails>();
于 2012-09-18T11:46:20.390 回答
0

尝试使用下面的代码。

public override List<IKPIDetails> MakeReportDataStructure() 
{ 
    return new List<AirTemp_KPIDetails>() as List<IKPIDetails>; 
}
于 2012-09-18T11:55:13.480 回答