我IEnumerable<A>
只含有B的對象。
我會質疑這個關於你的變量的聲明。您已指定它是IEnumerable<A>
,但它僅包含B
的實例。這樣做的目的是什麼?如果您在任何情況下明確只需要B
的實例,則最好是IEnumerable<B>
,因爲它可以防止在編譯時可能遇到的問題。
考慮下面的,我會想象,你可能有一些類似代碼:
var setOfA = // Get a set of A.
DoSomethingWithA(setOfA);
var instanceOfB = GetInstanceOfB(setOfA);
在這種情況下,我能理解的IEnumerable<A>
是完全有效的,當你想進行後者的操作,除了,GetInstanceOfB
。讓我們想象一下,這個定義是:
B GetInstanceOfB(IEnumerable<A> setOfA)
{
return // The answer to your question.
}
現在,最初的問題,我希望你看到的,是你把你所有的卡上的概念,您的列表(setOfA
在我的例子),總是隻打算包含B
的實例。雖然您可以保證從您的開發人員的角度來看,編譯器可以不做這樣的假設,但只能保證setOfA
(列表)是IEnumerable<A>
,並且其中存在潛在的問題。
綜觀提供的答案(所有這些都是非常有效的[@VirtualBlackFox是最安全的答案]給你的想法):
我IEnumerable<A>
只含有B的對象。
,如果在將來的某個變化,setOfA
,還包含C
實例(的A
未來潛在的子類)是什麼。鑑於這樣的回答:
list.Single(b => ((B)b).PropertyThatOnlyExistOnB == "something");
如果setOfA
居然是:[C B B]
。您可以看到,明確演員(B)b
將導致InvalidCastException
被引發。由於Single
操作的性質,它將繼續枚舉,直到第一個實例失敗謂詞(PropertyThatOnlyExistOnB == "something"
),或拋出異常爲止。在這種情況下,可能會拋出異常,這是意外的,並且可能未處理。這樣的回答,是類似於:
list.Cast<B>().Single(b => b.PropertyThatOnlyExistOnB == "something");
給出這樣的回答:
list.Single<A>(b => (b as B).PropertyThatOnlyExistOnB == "something")
在相同的情況下,異常往往發生的NullReferenceException
拋出實例,因爲C
實例不能安全地輸入投到B
。
現在,請不要誤會我的意思,我是而不是選那些答案,因爲我說他們是完全有效的,因爲你的問題的職權範圍。但在代碼更改的情況下,那些完全有效的答案成爲潛在的未來問題。
給出這樣的回答:
list.OfType<B>.Single(b => b.PropertyThatOnlyExistOnB == "something");
這可以讓你安全地類型轉換爲的A
,它們事實上B
一個潛在的子集,編譯器可以保證你的斷言只被上IEnumerable<B>
使用。
但是,這會讓我發現代碼中的關頭試圖處理您的IEnumerable<A>
,但執行的操作是您真正需要的IEnumerable<B>
。在這種情況下,你不應該重構這個代碼可能有一個明確的方法:
B GetMatchingInstanceOfB(IEnumerable<B> setOfB)
{
if (setOfB == null) throw new ArgumentNullException("setOfB");
return setOfB.Single(b => b.PropertyThatOnlyExistOnB == "something");
}
的方法設計的變化將確保自己只能明確接受一組有效的B
,而你不知道不必擔心你在這種方法中的演員。該方法僅負責匹配B
的單個項目。
當然,這意味着你需要把你趕出去,以不同的水平,但仍然是更明確:
var b = GetMatchingInstanceOfB(setOfA.OfType<B>());
我也假設你有足夠的錯誤處理到位的情況下,在所有實例爲B
的情況下謂詞將失敗,例如,多於一個項目滿足PropertyThatOnlyExistOnB == "something"
。
這可能是一個無意義的評論你的代碼的咆哮,但我認爲這是值得考慮的可能出現的意外情況,以及如何調整變量可以爲你節省潛在的頭痛在未來。
+1打我到它30秒:) – MatthewKing
不錯,乾淨,非常感謝! –