2011-12-01 76 views
3

我有以下类:如何浇铸词典<字符串,MyClass的>到词典<串,对象>

public class BagA : Dictionary<string, BagB> 
{} 
public class BagB : Dictionary<string, object> 
{} 

现在,通过反射我创建类型BagB的一个目的,其我 试图添加到我创建的类型巴加的对象:

object MyBagA // Created through reflection 
object MyBagB // Created through reflection 

((Dictionary<string,object>)MyBagA).Add("123",MyBagB); //This doesnt work 

使我有以下错误:无法投型“巴嘎”的对象键入“System.Collections.Generic.Dictionary`2 [System.String ,System.Object的]”。

为什么我不能投Dictionary<string, BagB>Dictionary<string, object>? 哪种方法可以根据此场景添加我的物品?也许匿名方法..?

请注意,我宁愿没有改变我的班巴加和BagB ...

谢谢!

+0

为什么不投MyBagB到袋B,而不是铸造的字典? – zmbq

回答

2

既然你使用反射来创建你的对象,这是唯一公平的,你需要继续使用它来调用它们的方法:

var addMethod = typeof(BagA).GetMethod("Add", new[] {typeof(string), typeof(BagB)}); 
addMethod.Invoke(MyBagA, new object[] {"123", MyBagB}); 
+0

这就是我最终做的并且工作得很好,虽然它稍微详细一点。谢谢你的帮助! –

1

这是根本不可能的。

如果你能够做到这一点,你将能够添加任意其他类型。

您需要使用反射调用该方法。

4

因为Dictionary<string, BagB>Dictionary<string, object>是不同的不兼容类型,所以没有办法在这里进行演员表演。为什么不转换价值而不是铸造Dictionary

MyBagA.Add("123", (BagB)MyBagB); 

如果投下Dictionary<TKey, TValue>是合法的,那么可能会发生非常恶劣的事情。考虑

Dictionary<string, BagB> map1 = ...; 
Dictionary<string, object> map2 = SomeEvilCast(map1); 
map2["foo"] = new object(); 

如果我试图访问map1["foo"],现在会发生什么?值的类型是object,但它的静态类型为BagB

+0

@JaredPar很好的观察,非常有意义 –

1

不能直接铸造或泛型类型的实例转换为一个实例除了通用类型被特别定义为该特定泛型类型参数的协变(能够被视为实际声明的泛型类型的基类的泛型),并且您正试图将键入它的实际类型的基类的泛型。例如,IEnumerable<string>可被视为IEnumerable<object>,因为字符串是从对象派生的。即使所有字符串只有一个字符,也不能将其视为IEnumerable<char>,因为字符串不是从Char派生的。

协变可以在C#4.0中使用generic参数中的out关键字定义,但据我所知,与IEnumerable不同,泛型IDictionary接口未指定为协变。另外,即使Dictionary是IEnumerable,它也是通用键/值对的IEnumerable,而通用KVPs不是协变的,因此您不能将KVP的通用参数视为基类型。

你可以做的是创建一个新的类型的字典,并从旧的字典中传输所有的值。如果这些值是引用类型,那么更改一个Dictionary的引用类型Value的子值将会将其更改为另一个Dictionary的相应Value(除非您通过将MyClass的新实例分配给该值来更改引用本身键)。

小LINQ使这一个很简单:

Dictionary<string, MyClass> MyStronglyTypedDictionary = 
    new Dictionary<string, MyClass>(); 
//populate MyStronglyTypedDictionary 

//a Dictionary<T1, T2> is an IEnumerable<KeyValuePair<T1, T2>> 
//so most basic Linq methods will work 
Dictionary<string, object> MyGeneralDictionary = 
    MyStronglyTypedDictionary.ToDictionary(kvp=>kvp.Key, kvp=>(object)(kvp.Value)); 

... 

//Now, changing a MyClass instance's data values in one Dictionary will 
//update the other Dictionary 
((MyClass)MyGeneralDictionary["Key1"]).MyProperty = "Something else"; 

if(MyStronglyTypedDictionary["Key1"].MyProperty == "Something else") 
{ 
    //the above is true; this code will execute 
} 

//But changing a MyClass reference to a completely new instance will 
//NOT change the original Dictionary 
MyGeneralDictionary["Key1"] = new MyClass{MyProperty = "Something new"}; 

if(MyStronglyTypedDictionary["Key1"].MyProperty == "Something else") 
{ 
    //the above is STILL true even though the instance under this key in the 
    //other Dictionary has a different value for the property, because 
    //the other dictionary now points to a different instance of MyClass; 
    //the instance that this Dictionary refers to never changed. 
} 
+0

这是不正确的。 'List '不能被视为'List ',因为你不能调用'stringList.Add(fileInfo);'。 'List '(或任何'IEnumerable ')可被视为“IEnumerable ”。因此,两个问题的答案是:(1)'List '没有声明协变。 (2)类永远不能被声明为共同或逆变,只能是接口和代表。 – phoog

相关问题