【问题标题】:How to cast Dictionary<string,MyClass> to Dictionary<string,object>如何将 Dictionary<string,MyClass> 转换为 Dictionary<string,object>
【发布时间】:2011-12-01 17:57:02
【问题描述】:

我有以下课程:

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&lt;string, BagB&gt; 转换为 Dictionary&lt;string, object&gt;? 根据这种情况,添加我的项目的最佳方式是什么?也许是匿名方法..?

请注意,我宁愿不必修改我的类 BagA 和 BagB...

谢谢!

【问题讨论】:

  • 为什么不将 MyBagB 转换为 bag B 而不是转换字典?

标签: c# generics reflection dictionary casting


【解决方案1】:

这里无法进行强制转换,因为Dictionary&lt;string, BagB&gt;Dictionary&lt;string, object&gt; 是不同的不兼容类型。而不是转换Dictionary 为什么不转换值呢?

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

如果使用Dictionary&lt;TKey, TValue&gt; 是合法的,那么可能会发生非常邪恶的事情。考虑

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

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

【讨论】:

  • 很好的观察@JaredPar,很有意义
【解决方案2】:

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

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

【讨论】:

  • 这就是我最终所做的并且工作正常,尽管它更详细一点。感谢您的帮助!
【解决方案3】:

这基本上是不可能的。

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

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

【讨论】:

    【解决方案4】:

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

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

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

    【讨论】:

    • 这是不正确的。 List&lt;string&gt; 不能被视为 List&lt;object&gt;,因为您不能调用 stringList.Add(fileInfo);List&lt;string&gt;(或任何IEnumerable&lt;string&gt;)可以被视为IEnumerable&lt;object&gt;。因此,答案存在两个问题:(1)List&lt;T&gt; 未声明为协变的。 (2) 类永远不能被声明为协变或逆变,只能声明接口和委托。
    • 我将补充@phoog 所说的内容。假设你有类型V1 : V2 : V3,形成一个继承链。您不能通过包装将List&lt;V2&gt; 弱化为List&lt;V3&gt;,因为后者最终会在您尝试添加时将V3 类型发送到V2 列表。您也不能将List&lt;V2&gt; 加强为List&lt;V3&gt;,因为前者的get 方法不能保证给您V3 类型的对象。但是,如果您将列表界面分为 getter 和 setter,我相信您可以分别削弱/加强类型。
    猜你喜欢
    • 2014-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多