【问题标题】:How to handle a generic dictionary whose types are unknown and don't matter?如何处理类型未知且无关紧要的通用字典?
【发布时间】:2010-02-24 05:05:21
【问题描述】:

如果 'value' 是传入的通用字典,其类型未知/无关紧要,我如何获取其条目并将它们放入 IDictionary<object, object> 类型的目标字典中?

if(type == typeof(IDictionary<,>))
{
    // this doesn't compile 
    // value is passed into the method as object and must be cast       
    IDictionary<,> sourceDictionary = (IDictionary<,>)value;

    IDictionary<object,object> targetDictionary = new Dictionary<object,object>();

    // this doesn't compile
    foreach (KeyValuePair<,> sourcePair in sourceDictionary)
    {
         targetDictionary.Insert(sourcePair.Key, sourcePair.Value);
    }

    return targetDictionary; 
}

编辑:

感谢您迄今为止的回复。

这里的问题是 Copy 的参数仅称为类型“对象”。例如:

public void CopyCaller(object obj) 
{ 
    if(obj.GetType() == typeof(IDictionary<,>) 
         Copy(dictObj); // this doesn't compile 
} 

【问题讨论】:

  • 如果您将IDictionary 用于弱类型字典而不是IDictionary&lt;object, object&gt;,则只需返回Dictionary&lt;T,K&gt;
  • 我无法使用 IDicitionary,因为我无法控制调用者的代码。

标签: c# generics dictionary


【解决方案1】:

您可以利用通用字典实现IDictionary 接口这一事实。

private static Dictionary<object, object> CreateCopy(IDictionary source)
{
    var copy = new Dictionary<object, object>(source.Count);
    foreach (DictionaryEntry entry in source)
    {
        copy.Add(entry.Key, entry.Value);
    }
    return copy;
}

使用示例:

var source = new Dictionary<int, string>() { { 1, "Foo" }, { 2, "Bar" }, };
var copy = CreateCopy(source);
Console.WriteLine(String.Join(", ", copy.Values));

输出:

Foo,酒吧

【讨论】:

    【解决方案2】:

    所以你有一个可能是字典的对象,你想要:

    • 测试它是一本字典
    • 如果是,请采取适当的行动

    让我们从一个通用函数开始,如果你知道类型参数,它会做你想做的事:

    class Bar
    {
        public static void Foo<TKey, TValue>(Dictionary<TKey, TValue> input) { ... }
    }
    

    现在我们只需要做一些反思

    bool TryHandleDictionary(object o)
    {
        var t = o.GetType();
        if (!t.IsGenericType || t.GetGenericTypeDefinition() != typeof(Dictionary<,>)) return false;
    
        var m = typeof(Bar).GetMethod("Foo", BindingFlags.Public | BindingFlags.Static);
        var m1 = m.MakeGenericMethod(t.GetGenericArguments());
        m1.Invoke(null, new[] { o });
        return true;
    }
    

    【讨论】:

      【解决方案3】:

      这里有一个方法(不要让它保持静态,除非你需要它,我在一个快速控制台应用程序中编写它)基本上将任何类型的字典转换为对象/对象字典。

          private static Dictionary<object,object> DeTypeDictionary<T,U>(Dictionary<T,U> inputDictionary)
          {
              Dictionary<object, object> returnDictionary = new Dictionary<object, object>();
              foreach(T key in inputDictionary.Keys)
              {
                  if( (key is object) && (inputDictionary[key] is object))
                  {
                      returnDictionary.Add(key, inputDictionary[key]);
                  }
                  else
                  {
                      //sorry these aren't objects. they may be dynamics.
                      continue;
                  }
      
              }
              return returnDictionary;
          }
      

      ...这就是你如何使用它...

              Dictionary<string, DateTime> d = new Dictionary<string, DateTime>();
              d.Add("rsgfdg", DateTime.Now);
              d.Add("gfdsgd", DateTime.Now);
      
              Dictionary<object, object> newDictionary = DeTypeDictionary<string, DateTime>(d);
      

      【讨论】:

      • 你能举一个例子说明key is object 会是假的吗?即使在 .NET 4 中使用动态,它也提供动态变量和参数,但是,afaik,不是用于泛型声明的动态类型。
      • 你是对的。在编译时,动态就是动态的,但是,和 var 一样,它们在 @runtime 时变成了对象,所以在运行时,它们始终是对象。
      【解决方案4】:

      让你的方法也通用,然后你就可以做你正在做的事情。您不必更改使用模式,因为编译器将能够从输入类型推断泛型类型。

      public IDictionary<object, object> Copy(IDictionary<TKey, TValue> source)
      {
      
          IDictionary<object,object> targetDictionary = new Dictionary<object,object>();
      
          foreach (KeyValuePair<TKey, TValue> sourcePair in sourceDictionary)
          {
               targetDictionary.Insert(sourcePair.Key, sourcePair.Value);
          }
      
          return targetDictionary; 
      }
      

      如果你真的不需要将它从IDictionary&lt;TKey, TValue&gt; 转换为IDictionary&lt;object, object&gt;,那么你可以使用Dictionary&lt;TKey, TValue&gt; 的复制构造函数,它接受另一个字典作为输入并复制所有值——就像你正在做的那样现在。

      【讨论】:

      • 我喜欢这个答案。很简洁。
      • 我去掉了“this doesn't compile”这一行,因为您的版本可以编译。希望你不要介意!
      【解决方案5】:

      这可能对您来说是一个修复,但您需要 .net 3.5 或更高版本才能使用 var 关键字。

      // this should compile
      foreach (var sourcePair in sourceDictionary)
      {
           targetDictionary.Insert(sourcePair.Key, sourcePair.Value);
      }
      

      【讨论】:

      • var 是一种方便的方法,可让编译器根据使用情况推断类型。这在上面使用它的许多节奏中是不可能的,例如在typeof() 检查或演员表中。
      • 同意。 var 使用与在运行时使用对象相同。
      • @karbon,不,var 不像使用objectvar 就像明确指定完整类型一样,只是你不这样做,编译器会在编译时从代码中计算出来。 var 对运行时代码的影响
      猜你喜欢
      • 2021-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多