今天,我从一些旧的动态转换代码中得到了这个错误(我更改了最后一行,并忽略了其余的堆栈跟踪):
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作为错误提交,除非其他人可以解释这是预期的行为。