2011-11-03 54 views
1

我有2個對象A和B. B是繼承自A並且有一些更多的屬性。 我有隻包含B對象的IEnumerable {A}。 我想要做的是:IEnumerable <T>。單獨和鑄造

list.Single(b => b.PropertyThatOnlyExistOnB == "something") 

我會想到是這樣的工作:

list.Single((B) b => b.PropertyThatOnlyExistOnB == "something") 

不過,這並不編譯。現在我只是在做:

B result = null; 
foreach (b in list) 
{ 
    if((B)b.PropertyThatOnlyExistOnB == "something") 
    { 
     result = (B)b; 
    } 
} 

有沒有更簡單的方法? 謝謝

回答

9

使用Enumerable.OfType<TResult>擴展方法來篩選/轉換。

list.OfType<B>().Single(b => b.PropertyThatOnlyExistOnB == "something") 
+0

+1打我到它30秒:) – MatthewKing

+0

不錯,乾淨,非常感謝! –

4

雖然我很喜歡@ VirtualBlackFox的回答最好,爲了完整起見:這裏是如何讓你的思想工作:

list.Single(b => ((B)b).PropertyThatOnlyExistOnB == "something"); 

你不是那麼遙遠的軌道,除非你有一些的語法困惑。 b => EXPRESSION語法表示一個lambda表達式。你無法啓動=>之前改變的東西,除非你想添加(或刪除)參數:

* `x => LAMBDA_WITH_ONE_PARAMETER` 
* `(x) => LAMBDA_WITH_ONE_PARAMETER` 
* `() => LAMBDA_WITH_NO_PARAMETERS` 
* `(x, y, z) => LAMBDA_WITH_THREE_PARAMETERS` 
+0

您有風險引發InvalidCastExceptions。你如何確保只有B的實例在枚舉中? –

+0

我不是。 OP表示他肯定,只有'B'的實例正在列舉中。有時你確定;)另外,如果枚舉中沒有'B'實例,'Single()'也會引發一個異常。只是說。 –

+0

@Mthethe Abbot:另外,我只是想告訴OP如何讓他的代碼正確。我記得說我更喜歡(和btw,+1)VirtualBlackFox的答案! –

1

這應該很好地工作:

list.Single<A>(b => (b as B).PropertyThatOnlyExistOnB == "something") 

如果你不想冒險例外被拋出,你可以這樣做:

list.Single<A>(b => ((b is B)&&((b as B).PropertyThatOnlyExistOnB == "something"))) 
+0

您不會冒險可能NullReferenceException其中該項目不是B的實例? –

+0

它的NullReferenceException或InvallidCastException(當你((B)B).Property。你的選擇;) – neurotix

+0

請參閱我的維基答案下面;-) –

2

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"

這可能是一個無意義的評論你的代碼的咆哮,但我認爲這是值得考慮的可能出現的意外情況,以及如何調整變量可以爲你節省潛在的頭痛在未來。