2012-09-18 27 views
1

在关于使用IEnumerable而不是List的初始建议之后进行编辑。在C#中返回一个列表<interface>

我试图做到这一点:

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>' 

它赢得了”不要让我隐式或明确地做。有什么办法可以做到这一点?

在此先感谢,

--- Alistair。

回答

1

你不应该投一个类型的列表到另一个原因,那么无论是插入操作将失败,或者越来越。

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

+0

谢谢,我可以看到我想要做什么可能是不可能的,或者至少是危险的。但我仍然希望!我可能只需要列出通用数据和另一个完全属于每个派生类的特定于报表的列表。 – user41013

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>),你不能写入任何对象。列表允许您将对象写入集合中,并且会遇到以下危险:稍后您可能会向该集合写入较少的特定类型,这可能会导致错误,因为较少的特定类型不提供与更多派生类型相同的功能:

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 
+0

其实,我不是协的专家,我试图解释这一碰到一些问题,我甚至可以从它制定一个问题,包涵:) – Bartosz

+0

感谢您的快速重播,它看起来不错,直到我试图构建它,当它说'NetVisSolution.Reports.SSAirTempSummaryReport.MakeReportDataStructure()':返回类型必须是'System.Collections.Generic.List '才能匹配重写成员'NetVisSolution.Reports.BaseReport.MakeReportDataStructure()'我已经尝试了几种变种,将IEnumerable和List放在不同的地方,但都没有工作。还有其他建议吗? – user41013

+0

在你的问题中加入修改后的代码,以便我们可以看到你究竟发生了什么变化。 – Bartosz

1

这两个列表是不同的,尽管AirTemp_KPIDetails我是IKPIDetails(即有一个is-a -relation)。你必须从一个列表复制的元素其他:

kpiDetailsList = new List<IKPIDetails>(airTempKPIList); 

一般来说,这属于合作和反方差的主题。您可能想要阅读Wiki文章Covariance and contravariance (computer science)

0

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

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

尝试使用下面的代码。

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