2008-11-13 115 views
2

我在寫一個泛型方法時遇到了一些麻煩。它有以下簽名;C#泛型方法中的Casting問題

public static ThingCollection<T> GetThings<T>(...) where T : Thing 

有幾個類;從Thing繼承的ThingA,ThingB和ThingC;我希望能夠在方法中使用類似這樣的代碼。

var things = new ThingCollection<T>(); 

if (typeof(T) == typeof(Thing)) 
    foreach (var item in someCollection) 
    things.Add((T)new Thing(...)); 
else if (typeof(T) == typeof(ThingA)) 
    foreach (var item in someCollection) 
    things.Add((T)new ThingA(...)); 
else if (typeof(T) == typeof(ThingB)) 
    foreach (var item in someCollection) 
    things.Add((T)new ThingB(...)); 
else if (typeof(T) == typeof(ThingC)) 
    foreach (var item in someCollection) 
    things.Add((T)new ThingC(...)); 
else 
    throw new Exception("Cannot return things of type " + typeof(T).ToString()); 

return things; 

的問題是,我得到了最好的重載的方法匹配具有參數無效錯誤,如果我不投的新對象。如上圖所示添加T個鑄造對於新的Thing()是正確的,但報告對於其他新的調用,不能將類型'ThingA'轉換爲'T'。智能感知表明T是一件事物,但我不明白爲什麼我們不能將其他物體拋向物體,因爲它們是從它繼承而來的。

也許這不是做我想做的事情的正確方法。我在正確的軌道上嗎?也許錯過了一些細微的細微差別,或者我應該完全做一些其他的事情?

回答

7

我不明白你想用這段代碼做什麼。

如果你想創建一個物件集合,你可以添加從Thing派生的任何類型的類,ThingCollection不應該有一個Typename:它應該是一個具體類型的集合。

E.g,實現ThingCollection這樣:

public class ThingCollection : List<Thing> {} 

現在你可以做

ThingCollection tc = new ThingCollection(); 
tc.Add(new ThingA()); 
tc.Add(new ThingB()); 
tc.Add(new ThingC()); 

假設當然,這ThingA,ThingB和ThingC從事情繼承的。

或者您可能想要使用GetThings()過濾派生類型的事物,即您希望對GetThings()的調用返回ThingCollection。

+0

這是一個很大的幫助。我一直在努力去處理泛型,因爲我沒有意識到我不需要使ThingCollection通用,因爲它繼承了通用列表。 – 2008-11-13 14:56:50

2

如果他們使用通用接口(IThing),您應該能夠轉換爲該接口。

3

主要我認爲,這段代碼片段的設計不好。如果添加「ThingD」類,則需要更改另一部分代碼,以獲得明確的行爲。 你應該使用類似:

public static ThingCollection<T> GetThings<T>(...) where T : Thing, new() 
... 
... 
T item = new T(); 
item.Something = Whatever(); 

或者你也可以執行「ICloneable」接口INT事情類。

3

該代碼違反了Liskov替換原則,因爲它試圖在使用它之前測試T的類型。

爲了避免這種情況,您可以使用字典/策略組合或訪問者模式。

如果T是ThingB,則演員(T)ThingA無效,因此代碼實際上是錯誤的。