如何将Dictionary <string,myclass>强制转换为Dictionary <string,object> </string,object> </string,myclass>

时间:2011-12-01 17:57:02

标签: c# generics reflection dictionary casting

我有以下课程:

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

现在,通过反思,我正在创建一个BagB类型的对象,我是 试图添加到我创建的BagA类型的对象:

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

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

给我以下错误:无法将'BagA'类型的对象强制转换为'System.Collections.Generic.Dictionary`2 [System.String,System.Object]'。

为什么我不能将Dictionary<string, BagB>投射到Dictionary<string, object>? 根据此方案添加项目的最佳方法是哪种?也许是匿名方法..?

请注意,我不想修改我的班级BagA和BagB ......

谢谢!

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

由于您使用反射来创建对象,因此您需要继续使用它来调用其方法,这是公平的:

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

答案 2 :(得分:1)

这根本不可能。

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

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

答案 3 :(得分:1)

你不能直接将泛型类型的实例转换或转换为具有不同泛型参数的类型的实例,除非泛型类型被特别定义为协变(能够被视为实际的基类的泛型)在该特定泛型类型参数上声明泛型类型,并且您尝试将该类型强制转换为其实际类型的基类的泛型。例如,IEnumerable<string>可以被视为IEnumerable<object>,因为字符串派生自对象。即使所有字符串只有一个字符,也不能将它视为IEnumerable<char>,因为String不是从Char派生的。

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

您可以做的是创建一个新类型的新词典并传输旧类型的所有值。如果这些值是引用类型,更改一个Dictionary的引用类型值的子值将在其他Dictionary的相应值中更改它(除非您通过将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.
}