2011-04-12 41 views
8

我有一個通用的字典:鑄造包含通用詞典

var someConcreteInstance = new Dictionary<string, Dictionary<string, bool>>(); 

,我希望將其轉換爲一個接口的版本,即:

someInterfaceInstance = (IDictionary<string, IDictionary<string, bool>>)someConcreteInstance; 

「someInterfaceInstance」是公共財產:

IDictionary<string, IDictionary<string, bool>> someInterfaceInstance { get; set; } 

這種編譯正確,但會引發運行時轉換錯誤。

Unable to cast object of type 'System.Collections.Generic.Dictionary`2[System.String,System.Collections.Generic.Dictionary`2[System.String,System.Boolean]]' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Collections.Generic.IDictionary`2[System.String,System.Boolean]]'. 

我在想什麼? (嵌套泛型/ Property的問題)

+0

難道你不能改變你的原始內部字典類型爲'IDictionary <>'?這將簡化一些事情,通常這不需要填充字典的代碼中的大的改變。 – digEmAll 2011-04-12 14:20:09

+0

@digEmAll:根據Eric的回答,這只是簡單地解決了問題,但並沒有解決問題。 – nicodemus13 2011-04-12 15:00:19

+0

不,我問你爲什麼不這樣做:'var someConcreteInstance = new Dictionary >();'而不是原始行?這將解決問題(你甚至不需要演員),但當然你可以有一些理由讓你的原代碼... – digEmAll 2011-04-12 15:07:15

回答

4

IDictionary不支持協方差。

看看這裏 IDictionary<TKey, TValue> in .NET 4 not covariant

+0

哦,是這個問題! (甚至在.net 4中?)你有什麼建議來獲得我想要的結果嗎? – nicodemus13 2011-04-12 14:04:19

+0

取決於你正在嘗試做什麼。張貼另一個問題,你想達到什麼目的,並要求最好的設計。 – Aliostad 2011-04-12 14:09:53

+0

謝謝,與編輯更有幫助的答案。 – nicodemus13 2011-04-12 14:16:51

1

最,你將能夠做的就是

IDictionary<string, Dictionary<string, bool>> viaInterface = someConcreteInstance 

你內心的字典無法區別此處引用的原因(或通過鑄造)是,雖然Dictionary<string, bool>IDictionary<string, bool>,並非全部IDictionary對象將是Dictionary對象。因此,獲得純粹的接口轉換似乎允許您將其他<string, IDictionary<string, bool>>對添加到原始集合中,當明確可能存在原始對象的類型違規時。因此,這不被支持。

11

其他的答案是正確的,但只是爲了一清二楚,爲什麼這是非法的,考慮以下因素:

interface IAnimal {} 
class Tiger : IAnimal {} 
class Giraffe : IAnimal {} 
... 
Dictionary<string, Giraffe> d1 = whatever; 
IDictionary<string, IAnimal> d2 = d1; // suppose this were legal 
d2["blake"] = new Tiger(); // What stops this? 

沒有凡人的手能阻止你把老虎變成IAnimals的字典。但該字典實際上僅限於包含長頸鹿。

出於同樣的原因,你不能去其他方式之一:

Dictionary<string, IAnimal> d3 = whatever; 
d3["blake"] = new Tiger(); 
IDictionary<string, Giraffe> d4 = d3; // suppose this were legal 
Giraffe g = d4["blake"]; // What stops this? 

現在你把一個虎型長頸鹿的變量。

如果編譯器可以證明這種情況不會出現,那麼通用接口協方差在C#4中只是合法的。

+0

你確定你寫的最後一行是清楚的嗎?我的原始代碼編譯得很好,但會引發運行時錯誤,所以編譯器似乎允許這種情況。 – nicodemus13 2011-04-12 14:59:24

+2

@ nicodemus13:你的代碼中有一個演員操作符;我的不是。演員操作員的意思是「進行這種轉換,這在編譯時是非法的,並且是合法的;如果在運行時證明是非法的,則拋出異常」。嘿,你猜怎麼着?這就是發生的事情。你告訴編譯器「假設這種非法轉換會很好地完成」,然後它不會,你會得到一個異常。 **引用類型轉換運算符的目的是將類型檢查的負擔從編譯器移動到運行時。**負擔不會消失,它只會移動。 – 2011-04-12 15:13:28

+1

「長頸鹿,長頸鹿,燃燒明亮/在夜晚的森林」。好的事情C#類型系統可以防止這樣的悲劇! – 2011-04-12 15:23:49