简体   繁体   English

返回清单 <interface> 在C#中

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

Edited after initial suggestions about using IEnumerable instead of List. 在有关使用IEnumerable而不是List的初步建议之后进行了编辑。

I am trying to do this: 我正在尝试这样做:

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
    }

    //...
}

So I have a report data object interface and potentially multiple report data classes implementing this interface and adding their specific extra bits. 因此,我有一个报表数据对象接口,并可能有多个报表数据类实现此接口并添加其特定的额外位。 And I have an abstract report class implementing generic report functionality and multiple derived classes that each use their own report data class. 我有一个抽象的报告类,实现了通用的报告功能,并且有多个派生类,每个派生类都使用自己的报告数据类。

Unfortunately, when I try to create a list of my report detail structures in the derived class and pass it back to the base class as a list of the interface, it complains: 不幸的是,当我尝试在派生类中创建报表详细信息结构的列表并将其作为接口列表传递回基类时,它抱怨:

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

It won't let me do it implicitely or explicitly. 它不会让我隐式或显式地执行此操作。 Is there any way that I can do this? 有什么办法可以做到这一点?

Thanks in advance, 提前致谢,

--- Alistair. ---阿利斯泰尔。

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

Should be: 应该:

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

Your assignment does not work, because in List<T> , type argument T is not covariant, that is, assignment is not allowed when T is more specific. 您的分配不起作用,因为在List<T> ,类型参数T不是协变的,也就是说,当T更具体时,不允许分配。 Should you use IEnumerable , your code would work fine: 如果您使用IEnumerable ,您的代码将正常工作:

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

You may ask, why IEnumerable is covariant? 您可能会问,为什么IEnumerable是协变的? Well, IEnumerable only allows you to read data (hence covariance is marked with <out T> ), and you cannot write any object into it. 嗯, IEnumerable只允许您读取数据(因此协方差用<out T>标记),并且您不能向其中写入任何对象。 List allows you to write objects into collection, and you would run into danger that you would later write less specific type to that collection, which could cause error, as less specific type does not provide same functionality as more derived one: 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

These two lists are different, even though AirTemp_KPIDetails my be a IKPIDetails (ie have an is-a -relation). 这两个列表是不同的,即使AirTemp_KPIDetailsIKPIDetails (即具有is-a -relation关系)也是如此。 You must copy the elements from one list to the other: 您必须将元素从一个列表复制到另一个列表:

kpiDetailsList = new List<IKPIDetails>(airTempKPIList);

In general this belong to the subject of Co- and Contra-Variance. 总的来说,这属于同方差和相反方差的主题。 You may want to read the Wiki Article on Covariance and contravariance (computer science) . 您可能需要阅读Wiki上有关协方差和相反方差的文章(计算机科学)

you shouldn't cast a List of one type to another because, then either the insert operation would fail, or the getting. 您不应该将一种类型的列表转换为另一种类型,因为插入操作将失败或获取。

example: type A implements(extends) type B 示例:类型A实现(扩展)类型B

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


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

if this would legal, then you break the listA invariant by putting something more general than A. 如果这是合法的,则可以通过放置比A更通用的内容来破坏listA不变式。

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

this would break the fact that only A objects, could be assigned to the A reference. 这将打破只有A对象可以分配给A引用的事实。

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

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

Try to use the below code. 尝试使用下面的代码。

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