2012-09-18 21 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>; 
}