2012-02-23 10 views
2

今日は(私は最後の行を変更したとスタックトレースの残りのうち左)いくつかの古いダイナミックキャストのコードから、このエラーを得た:MethodInfo.MakeGenericMethodを呼び出すとき、このキーエラーはどういう意味ですか?

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>>は、メッセージイベント(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; 
    } 
} 
+0

うわー、それは醜いです。私にはフレームワークのバグのように見えます。 MethodInfoはスレッドセーフであると文書化されています。このマルチスレッドコードですか? –

+0

ええ、そこのDynamicInvokeは、必ずしもスレッドセーフではない何かを呼びます(変換されるクラスのgetメソッドは何でもできます)。 –

+1

@BillBarry thats trueですが、スタックトレースはMakeGenericMethod呼び出しからのこのエラーを明示的に示しています... –

答えて

2

がMakeGenericMethodの内部に適切に固定するためのフレームワークでの失敗です。

MakeGenericMethodが呼び出されると、フレームワークは指定されたジェネリックパラメータでメソッドの新しいバージョンを作成するか、ジェネリックメソッドを作成する前に同じジェネリックパラメータタイプを使用したとします。以前に生成されたメソッドを返します。複数のスレッド上でMakeGenericMethodを呼び出すと、メソッドがまだ生成されていないとみなし、後で呼び出すために生成されたメソッドを格納する際に競合する競合状態が発生する可能性があります。 。

つまり、この場合はすべてがロックされているように見えるので、これも問題であると私は十分に確信していません。

誰か他の人がこれが予想される動作であることを説明できない限り、私はバグとしてMSFTにファイルします。

+0

私は.NET 4.0でバグに直面し、https://connect.microsoft.com/VisualStudio/feedback/details/738253として提出しました。 –

関連する問題