2009-03-03 58 views
1

我有以下代碼列表<T>鑄造算法和性能方面的考慮

class Program 
    { 
     static void Main(string[] args) 
     { 
      List<A> aList = new List<A>(); 

      var aObj = new A(); 

      aObj.Go(aList.Cast<IB>()); 
     } 
    } 

    class A : IB 
    { 
     public void Go(IEnumerable<IB> interfaceList) 
     { 
      foreach (IB ibby in interfaceList) 
      { 
       Console.WriteLine("Here"); 
      } 
     } 
    } 

    interface IB 
    { 
     void Go(IEnumerable<IB> interfaceList); 
    } 

}

我最初試圖通過一個列表但doesn't work。 經過SO的大量幫助,我發現傳遞IEnumerable是以.ofType(IB)形式獲取對象的唯一方法。

不幸的是,我在我的下面這行代碼會被執行數千次:

aList.Cast<IB>(); 

我想知道是否有人知道它是如何通過算法來實現(在IL)和它的時間順序是什麼。

也就是說,它是否比foreach循環更快地轉換每個項目,或者它正是它所做的?

編輯主類需要維護一個實際對象的列表。但讀者只能通過界面觸摸它們。

回答

10

你應該改變Go到:

public void Go<T>(IEnumerable<T> interfaceList) 
    where T : IB 
{ 
    foreach (IB ibby in interfaceList) 
    { 
     Console.WriteLine("Here"); 
    } 
} 

然後你會被罰款,而無需調用Cast。我懷疑Cast的源代碼實現非常簡單,但我相信它在3.5和3.5SP1之間發生了變化。但是,它可能需要以正常的迭代器塊方式設置新的狀態機等。如果可能,最好避免它。

即使新方法是通用的,鍵入推斷通常應該照顧它,所以你不需要明確地指定T

+0

這可能會徹底改變這個問題,但是如果A需要有一個IB的內部列表,它正好反映了A的主要列表? – DevinB 2009-03-03 20:01:58

+0

@devinb:我不確定你的意思。你的意思是作爲一個成員變量?你必須做一個通用的;那麼你可以使用相同的技巧。如果這還沒有足夠的信息,我建議你就這一點提出一個新的問題,提供更多細節。 – 2009-03-03 20:06:49

5

爲什麼不宣佈名單,如:

List<IB> aList = new List<IB>(); 

有什麼特別要求你有具體的類的列表?


所以在這種情況下,我會讓列表成爲域的一部分。有一個像IIBCollection這樣的接口(例如),公開您希望讀者能夠訪問的方法。例如:

interface IIBCollection{ 
    IEnumerable<IB> IBs { get; } 
} 

// and in your implementation you can do 

IEnumerable<IB> IBs { 
    get { 
     foreach(IB ib in innerList) yield return ib; 
}} 
1

它在內部作爲CastIterator實現,它比投射每個項目的foreach稍慢。

0

Cast方法將循環遍歷列表並投射每個項目。

如果您打算使用列表數千次,只需將結果作爲列表存儲。

如果這不可行(即每次更改列表),請考慮使用List<IB>而不是List<A>

0

這不就是C#中的協變嗎?我沒有看到你想要做什麼,所以我不能評論它爲什麼要經過數千次和數千次。

0

只要對兩個方法進行基準測試(Cast擴展方法和一個帶演員表的循環),這將是一件相當簡單的事情。但是鑑於Cast是Enumerable類的擴展方法,並且一般地處理IEnumerables,我可以想象這正是它的實現。如果你想要最快的速度,最好實現你自己的專門針對List的擴展方法(通過其索引獲取每個元素),考慮到迭代器的開銷,這應該稍微快一點。儘管如此,這兩種方法都需要花費O(n)次,所以差別不應該很大。這是值得標杆的東西,儘管如此......