2013-03-01 58 views
9

在我的項目中,我有一個MyClass,它實現了IMyClass。我需要通過轉換其他項目列表來返回IMyClass的列表。爲了簡單起見,假設我可以創建一個MyClass,只需將另一個項目傳遞給它的構造函數即new MyClass(item)即可。我應該投我的lambda或投IEnumerable?

考慮以下兩行,其中(據我所知)產生相同的結果:

var option1 = items.Select(item => new MyClass(item)).Cast<IMyClass>().ToList() 
var option2 = items.Select(item => new MyClass(item) as IMyClass).ToList() 

這在我看來,選項1將需要雙重枚舉,一旦投中的所有項目到我的界面和一次生成列表。如果我是對的,那麼選項#2會更聰明。然而,我已經從來沒有看到使用類似選項#2的任何代碼,並且我傾向於認爲我不夠聰明,想出其他C#社區沒有的聰明之處。

在附註中,我認爲選項#2更美觀,但這只是我。

我的問題是:是我的選擇#2一個更好的想法,就像我認爲它是?是否有任何遺漏或其他原因,爲什麼我想堅持選項#1?或者我可能比較兩個愚蠢的想法,當有一個更聰明的第三個我完全失蹤?

+3

不要忘記枚舉數是懶惰和可組合的!選項1不會導致它被枚舉兩次...... – 2013-03-01 17:20:22

+0

如果'MyClass'實現'IMyClass',爲什麼需要投射? – 2013-03-01 17:21:57

+1

你知道你總是可以在沒有推理的情況下拼出類型嗎?也就是,'var result = items.Select (x => new MyClass(x))。ToList();'這將返回'IEnumerable ':) – 2013-03-01 17:23:12

回答

17

我會去選擇3:

var option3 = items.Select<Foo, IMyClass>(item => new MyClass(item)) 
        .ToList() 

另外,不要使用as但只投正常:

var option4 = items.Select(item => (IMyClass) new MyClass(item)) 
        .ToList() 

這兩個都比使用Cast更清潔。

哦,而隨着C#4 .NET 4中(由於協方差),你可以把在ToList通話,而不是一個類型參數:

var option5 = items.Select(item => new MyClass(item)) 
        .ToList<IMyClass>() 
+0

選項3和4在美學上並不適合我,但選項5肯定會。萬歲選擇! – ean5533 2013-03-01 17:32:58

+0

選項4不應該是'var option4 = items.Select(item =>(** IMyClass **)new MyClass(item))'? – pescolino 2013-03-01 17:45:07

+0

@pescolino:是的確 - 固定,謝謝。 – 2013-03-01 18:08:48

3

這在我看來,選項1將需要雙重枚舉

這是不正確的。在這兩種情況下,只有當您訪問ToList()時纔會列舉items集合。

var option1 = items.Select(item => new MyClass(item)).Cast<IMyClass>().ToList() 

相當於

var option1 = items.Select(item => new MyClass(item)).Select(x => (IMyClass)x).ToList() 

兩者之間的唯一區別是,第一個需要每個項目兩個函數調用(除非C#內聯的lambda表達式某種程度上,這是我不相信是這樣),而第二個選項只需要一個。

就我個人而言,我會與第二個一起作爲風格的問題。

+0

+1。我個人的理由選擇2 - 我不喜歡在這樣的背景下投射。它表明一個人無法決定收藏哪些物品。請注意,在很多情況下,如果您不需要特定類型的'List ',您可以在需要'IEnumerable '的地方使用'IEnumerable ' - 所以您可能實際上需要在某些情況下需要強制轉換以使代碼更易於閱讀。 – 2013-03-01 17:30:10

1

你使用哪一個是一個偏好問題,我們真的不能爲你回答。

但是你的直覺如果排序正確的話Cast爲你的循環增加了第二層迭代。這是非常小的,我懷疑它會產生任何性能上的可測量的差異,但Cast方法返回一個新IEnumerable對象,基本上做到這一點:

foreach (object obj in source) yield return (TResult)obj; 

效果是調用堆棧上大多是另一個層面;因爲它使用yield它只會根據需要進行迭代,就像大多數其他IEnumerable方法一樣。但它將不得不返回兩層迭代器狀態而不是一個狀態。對於您而言,是否需要爲自己的應用程序進行衡量。

(還要注意的是,至少根據參考源,它確實不安全的演員陣容,其中可能拋出一個異常,如果轉換是無效的。這是另一個理由,更喜歡你的選擇2#)

1

您可以隨時到您的選擇提供明確的類型參數

var option2 = items.Select<IItem,IMyClass>(item => new MyClass(item)).ToList(); 

其中IItem是可以投射物品的類型或界面。