今天,我从一些旧的动态转换代码中得到了这个错误(我更改了最后一行,并忽略了其余的堆栈跟踪):

Item has already been added.
Key in dictionary:
   'Int32 Count[Object](System.Collections.Generic.IEnumerable`1[System.Object])'
Key being added:
   'Int32 Count[Object](System.Collections.Generic.IEnumerable`1[System.Object])'
---> System.ArgumentException: Item has already been added.
     Key in dictionary:
         'Int32 Count[Object](System.Collections.Generic.IEnumerable`1[System.Object])'
     Key being added:
         'Int32 Count[Object](System.Collections.Generic.IEnumerable`1[System.Object])'
  at System.Reflection.CerHashtable`2.Insert(K[] keys, V[] values, Int32& count, K key, V value)
  at System.Reflection.CerHashtable`2.Preallocate(Int32 count)
  at System.RuntimeType.RuntimeTypeCache.GetGenericMethodInfo(RuntimeMethodHandle genericMethod)
  at System.RuntimeType.GetMethodBase(RuntimeTypeHandle reflectedTypeHandle, RuntimeMethodHandle methodHandle)
  at System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type[] methodInstantiation)
  at MyNamespace.CommunicationExtensions.BuildMessage[T](T obj)


全班

public static class CommunicationExtensions {
    static readonly object lockobj = new object();
    public static bool CanBuildMessage<T>(this T obj) where T: class {
        return obj != null && (MessageFactory.MessageBuilders.ContainsKey(obj.GetType()));
    }
    public static string BuildMessage<T>(this T obj) {
        lock (lockobj) {
            Delegate d;
            var type = obj.GetType();

            if (MessageFactory.MessageBuilders.TryGetValue(type, out d)) {
                var castMethod = typeof(CommunicationExtensions).GetMethod("Cast").MakeGenericMethod(type);
                var castedObject = castMethod.Invoke(null, new object[] { obj });

                return d.DynamicInvoke(castedObject) as string;
            }
        }
        return null;
    }
    public static T Cast<T>(object o) {
        return (T)o;
    }
}


MessageFactory.MessageBuilders是一个Dictionary<Type,Func<Type,string>>,其中包含编译的lambda表达式,这些表达式可以根据需要延迟构建,以将Message事件(基于EventArgs的简单自动属性类)转换为其他系统中使用的字符串格式。我认为这无关紧要。我认为导致此问题的唯一必要代码是:

public static class CastError{
    public static void GetCast<T>(this T obj) {
        var type = obj.GetType();
        var castMethod = typeof(CastError).GetMethod("Cast").MakeGenericMethod(type);
        //...
    }
    public static T Cast<T>(object o) {
        return (T)o;
    }
}

最佳答案

看起来是框架无法正确锁定MakeGenericMethod的内部。

调用MakeGenericMethod时,该框架应使用指定的通用参数创建该方法的新版本,或者如果在创建该通用方法之前使用了相同的通用参数类型,则该框架应返回以前的-生成的方法。似乎您碰到了一个极端情况,即在多个线程上调用MakeGenericMethod可能会导致竞争状态,其中两个线程都认为该方法尚未生成,请继续进行生成,然后在存储生成的方法时发生冲突未来的电话。

就是说,在这种情况下,看起来好像都处于锁定状态,所以我也不完全相信这也是问题所在。

我将MSFT作为错误提交,除非其他人可以解释这是预期的行为。

10-06 06:51