2013-01-13 40 views
1

使用.NET Framework 3.5的Equals方法比較MethodBase情況下,當我遇到一個相當奇怪的行爲 - 它只是失敗的情況下,NullReferenceException比較編譯器定義時帶有開放式泛型方法對象的構造器方法對象。System.Reflection.RuntimeMethodInfo.Equals失敗,NullReferenceException異常在.net 3.5

這裏是攝製代碼:

class TheClass 
{ 
    public T TheMethod<T>() 
    { 
     return default(T); 
    } 
} 

class Program 
{ 
    private static void Main(string[] args) 
    { 
     var ctor = typeof(TheClass).GetConstructors().Single(); 
     var generic = typeof(TheClass).GetMethods().Single(x => x.Name == "TheMethod"); 

     Console.WriteLine(generic.Name); // TheMethod 
     Console.WriteLine(generic.GetType().Name); // RuntimeMethodInfo 

     Console.WriteLine(ctor.Name); // .ctor 
     Console.WriteLine(ctor.GetType().Name); // RuntimeConstructorInfo 

     Console.WriteLine(generic.Equals(ctor)); // throws NullReferenceException 
     Console.ReadKey(); 
    } 
} 

它工作正常,在.NET 4.0中。 我一直在使用反編譯看着RuntimeMethodInfo.Equals實現在3.5和4.0,這是一個有趣的部分:

.NET 3.5

if (!this.IsGenericMethod) 
    return obj == this; 
    RuntimeMethodInfo runtimeMethodInfo = obj as RuntimeMethodInfo; 
    if (this.GetMethodHandle().StripMethodInstantiation() != runtimeMethodInfo.GetMethodHandle().StripMethodInstantiation() || runtimeMethodInfo == null || !runtimeMethodInfo.IsGenericMethod) 
    return false; 
// ... 

.NET 4.0

if (!this.IsGenericMethod) 
    return obj == this; 
    RuntimeMethodInfo runtimeMethodInfo = obj as RuntimeMethodInfo; 
    if ((MethodInfo) runtimeMethodInfo == (MethodInfo) null || !runtimeMethodInfo.IsGenericMethod || RuntimeMethodHandle.StripMethodInstantiation((IRuntimeMethodInfo) this).Value.Value != RuntimeMethodHandle.StripMethodInstantiation((IRuntimeMethodInfo) runtimeMethodInfo).Value.Value) 
    return false; 

在.NET 4.0 null -check使用可能的空runtimeMethodInfo變量之前被感動了。對我而言,3.5行爲似乎是一個框架bug,不是嗎?

所以問題是 - 有沒有解決方法或安全地比較這些對象的方法?請注意,在實際的代碼,我沒有要求Equals直接,但在收藏品等使用它隱含的地方,所以捕NullReferenceExceptions聽起來並不好。

+1

有沒有什麼不能切換到.NET 4的理由?我知道這不是一個答案,但它是一個解決方案。 – ChrisF

+0

看起來好像沒有一個好的解決方法,除了編寫替代的'Equals'方法外。或者至少在調用運行時的「Equals」方法之前檢查'ctor'值。你可以爲你的集合創建一個'EqualityComparer',這樣它就不會調用運行時版本。 –

+1

@ChrisF我不想切換,因爲這是更類似庫的項目,我不想要消費者需要.NET 4。 – NOtherDev

回答

1

看起來不像有一個很好的解決方法,比寫一個替代方法Equals等。或者至少是你調用運行時的Equals方法之前,將檢查ctor值。

收集,創建一個EqualityComparer做定製的比較。這將消除對默認Equals方法的調用。

+0

謝謝。我只用'return x.IsConstructor == y.IsConstructor && x.Equals(y)'來實現它。然後,第一個條件就會過濾出車輛的情況。 – NOtherDev