【问题标题】:Implementing a generic ToConcurrentDictionary extension method实现通用 ToConcurrentDictionary 扩展方法
【发布时间】:2014-02-19 08:15:29
【问题描述】:

我试图向我的应用程序添加一些类型安全的字典逻辑,并试图寻找一种实现来将给定字典转换为并发字典。在没有运气的情况下搜索了一段时间后,我最终用一些破解的代码实现了我自己的版本。以下是我想出的版本:

    public static class Extensions
      {
        public static ConcurrentDictionary<TKey, TValueResult> ToConcurrentDictionary<TKey, TValueInput, TValueResult>(this IEnumerable<KeyValuePair<TKey, TValueInput>> input)
        {
          var result = new ConcurrentDictionary<TKey, TValueResult>();
          foreach (var kv in input)
          {
            if (typeof(TValueInput).IsDictionaryType())
            {
              var mi = MethodInfo.GetCurrentMethod() as MethodInfo;
              var valGenericArgs = typeof(TValueInput).GetGenericArguments();
              if (valGenericArgs.Length > 0 && valGenericArgs.Last().IsDictionaryType())
              {
                Type generic = typeof(ConcurrentDictionary<,>);
                var conDicType = generic.MakeGenericType(typeof(TValueResult).GetGenericArguments().Last().GetGenericArguments());
                valGenericArgs = valGenericArgs.Concat(new Type[] { conDicType }).ToArray();
              }
              else
              {
                valGenericArgs = valGenericArgs.Concat(new Type[] { valGenericArgs.Last() }).ToArray();
              }
              var genMi = mi.MakeGenericMethod(valGenericArgs);
              var newDic = genMi.Invoke(null, new object[] { kv.Value });
              result.TryAdd(kv.Key, (TValueResult)newDic);
            }
            else
            {
              result.TryAdd(kv.Key, (TValueResult)Convert.ChangeType(kv.Value, typeof(TValueResult)));
            }
          }
          return result;
        }

        public static bool IsDictionaryType(this Type type)
        {
          return type.FullName.StartsWith("System.Collections.Generic.IDictionary`")
            || type.GetInterfaces().Any(t => t.FullName.StartsWith("System.Collections.Generic.IDictionary`"));
        }
}

使用方法如下:

  var dic1 = new Dictionary<string, Dictionary<int, IDictionary<string, int>>> 
    { 
        {"one", new Dictionary<int, IDictionary<string, int>>
                {
                    {11, new Dictionary<string,int>
                                {
                                    {"one-one-one", 10000}
                                }
                    }
                }
        }
    };
  var dic2 = new Dictionary<int, IDictionary<int, IDictionary<int, string>>> 
    { 
        {1, new Dictionary<int, IDictionary<int, string>>
                {
                    {11, new Dictionary<int,string>
                                {
                                    {111, "one-one-one"}
                                }
                    }
                }
        }
    };

  var dic3 = new Dictionary<int, string> 
                                {
                                    {111, "one-one-one"}
                                };

  var cd1 = dic1.ToConcurrentDictionary<string, Dictionary<int, IDictionary<string, int>>, ConcurrentDictionary<int, ConcurrentDictionary<string, int>>>();
  var cd2 = dic2.ToConcurrentDictionary<int, IDictionary<int, IDictionary<int, string>>, ConcurrentDictionary<int, ConcurrentDictionary<int, string>>>();
  var cd3 = dic3.ToConcurrentDictionary<int, string, string>();

有任何改进此方法的建议或任何更好的替代方法以达到相同的结果吗?

【问题讨论】:

  • 我猜这是一个 C# 问题?
  • 是的@vemv。感谢您指出这一点。

标签: c# c#-4.0 concurrency concurrentdictionary


【解决方案1】:

查看 MSDN,有一个 ConcurrentDictionary 的构造函数,它接受 KeyValuePairs 的 IEnumerable。这会实现您想要的吗?

public static ConcurrentDictionary<TKey, TValue> ToConcurrentDictionary<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> input)
{
        return new ConcurrentDictionary<TKey, TValue>(input);
}

【讨论】:

  • 是的,杰里米,但该实施只能部分解决问题。这适用于一个级别,但如果您将 TValue 作为另一个 Dictionary 或我在示例中的多个级别,则此实现只是忽略将内部字典转换为并发。
【解决方案2】:
//Translate A to B
var a = new Dictionary<Dictionary<string, string>>();
var b = a.SerializeJson()
         .DeserializeJson<ConcurrentDictionary<ConcurrentDictionary<string,string>>();

【讨论】:

    【解决方案3】:

    我知道这是一个旧线程,但是查看 ToDictionary 的 Microsoft 源代码,我能够为 ToConcurrentDictionaryToConcurrentBag

    制作扩展器
    public static ConcurrentDictionary<TKey, TSource> ToConcurrentDictionary<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            return ToConcurrentDictionary<TSource, TKey, TSource>(source, keySelector, IdentityFunction<TSource>.Instance, null);
        }
    
        public static ConcurrentDictionary<TKey, TSource> ToConcurrentDictionary<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
        {
            return ToConcurrentDictionary<TSource, TKey, TSource>(source, keySelector, IdentityFunction<TSource>.Instance, comparer);
        }
    
        public static ConcurrentDictionary<TKey, TElement> ToConcurrentDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
        {
            //return ToConcurrentDictionary<TSource, TKey, TElement>(source, keySelector, elementSelector, null);
            if (source == null) throw new Exception("Source is null");
            if (keySelector == null) throw new Exception("Key is null");
            if (elementSelector == null) throw new Exception("Selector is null");
    
            ConcurrentDictionary<TKey, TElement> d = new ConcurrentDictionary<TKey, TElement>();
            foreach (TSource element in source) d.TryAdd(keySelector(element), elementSelector(element));
            return d;
        }
    
        public static ConcurrentDictionary<TKey, TElement> ToConcurrentDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
        {
            if (source == null) throw new Exception("Source is null");
            if (keySelector == null) throw new Exception("Key is null");
            if (elementSelector == null) throw new Exception("Selector is null");
    
            ConcurrentDictionary<TKey, TElement> d = new ConcurrentDictionary<TKey, TElement>(comparer);
            foreach (TSource element in source) d.TryAdd(keySelector(element), elementSelector(element));
            return d;
        }
        public static ConcurrentBag<TSource> ToConcurrentBag<TSource>(this IEnumerable<TSource> source)
        {
            if (source == null) throw new Exception("Source is null");
            return new ConcurrentBag<TSource>(source);
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-18
      • 1970-01-01
      • 2014-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-25
      相关资源
      最近更新 更多