c# - 调用 MethodInfo.MakeGenericMethod 时出现此关键错误意味着什么?

标签 c# reflection dynamic

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

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.MessageBuildersDictionary<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 归档,除非其他人可以解释这是如何预期的行为。

关于c# - 调用 MethodInfo.MakeGenericMethod 时出现此关键错误意味着什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9419464/

相关文章:

java - 如何在Java中实现动态责任链?

c# - MVC Controller 冒泡回到路由器?

reflection - `is` 所持有的底层类型是否有 `TAny` 功能?

java - 将 String 转换为任何所需类的通用代码

c# - 如何在 C# 中找到对象的所属程序集

jsf - 如何使用 PrimeFaces 实现递归菜单

java - Java 中的动态数组 - 我有哪些选择?

c# - 以编程方式更改 SPFolder 的名称

c# - 从 C# 代码获取 IIS 中的请求数

c# - 如何从 HttpRequestException 获取 JSON 错误消息