2011-04-21 56 views
3

我本來希望找到一個容易解決這個問題的答案,但我沒有。 我想知道是否有可能確定一個方法是否有關鍵字'override'歸因於它,因爲它的實例爲MethodInfo確定一個C#方法是否使用了反射關鍵字'覆蓋'

我想也許下面將實現這一目標:

/// <summary> Returns whether the specified methodInfo is attributed with the keyword 'override'. </summary> 
public static bool IsOverriding(this MethodInfo methodInfo) 
{ 
    if (methodInfo == null) throw new ArgumentNullException(); 
    return methodInfo.DeclaringType != methodInfo.GetBaseDefinition().DeclaringType; 
} 

我已經成功地測試了一些非虛,虛擬和抽象的例子,但我覺得我失去了一些場景,也許有隱藏或泛型(儘管我無法弄清楚這將如何發揮作用)。

+0

這似乎是一個重複的http://stackoverflow.com/questions/2932421/detect-if-a-method-was-overridden-using-reflection-c – 2011-04-21 15:51:28

+0

@詹姆斯,嗯......這的確是一個類似的問題,雖然不完全一樣。我用'覆蓋'這個詞進行搜索,並且不幸的是帖子沒有找到,可能是因爲它使用了'重寫'這個詞。然而,那裏的答案並不適合我。 – JBSnorro 2011-04-21 16:02:14

回答

0

嘛,我看不出,將開始發揮作用無論是。您的代碼確實確定方法是定義還是重寫。

在隱藏的情況下,聲明類型是通過new隱藏該方法的類型。 在泛型的情況下,所有方法都由模板類定義。

0

你可以試試這個

public static bool IsOverriding(this MethodInfo methodInfo) 
{ 
    if (methodInfo == null) throw new ArgumentNullException(); 
    return methodInfo.GetBaseDefinition() != methodInfo; 
} 
+0

-1。這是行不通的。考慮抽象類A {public abstract void Foo(); }抽象類B:A {},然後typeof運算(B).GetMethod( 「富」)IsOverriding()將返回true,它不應該。 – JBSnorro 2011-04-21 16:07:18

2

我也試着找到這個東西。從這個問題,你給的想法得到IsOverriding工作override關鍵字。但是對於隱藏,我嘗試爲關鍵字new創建IsHiding。下面是基本C#OOP:

  • override僅當基於方法包含abstractvirtual改性劑使用。
  • new用於隱藏基礎的方法具有相同的名稱,但...
  • new不能適用於abstract基礎方法,因爲它產生編譯器錯誤。
  • 然而,有趣的部分是new如果基本方法包含virtual也可以應用於方法。

令人不滿的部分是我們可以隱藏或覆蓋virtual方法。我們知道如果我們override a virtual方法GetBaseDefinition()將返回基地MethodInfo。但區分它的關鍵是GetBaseDefinition()將返回相同的MethodInfo而不是它基於MethodInfo如果我們隱藏virtual方法。

override關鍵字是必須的,而new僅用於抑制警告消息。所以我們可以通過IsAbstractIsVirtual結合​​和BaseType來區分overridenew

public static bool IsOverriding(this MethodInfo methodInfo) 
    { 
     if (methodInfo == null) throw new ArgumentNullException("methodInfo"); 
     return methodInfo.DeclaringType != methodInfo.GetBaseDefinition().DeclaringType; 
    } 

    public static bool IsHiding(this MethodInfo methodInfo) 
    { 
     if (methodInfo == null) throw new ArgumentNullException("methodInfo"); 
     if (methodInfo.DeclaringType == methodInfo.GetBaseDefinition().DeclaringType) 
     { 
      var baseType = methodInfo.DeclaringType.BaseType; 
      if (baseType != null) 
      { 
       MethodInfo hiddenBaseMethodInfo = null; 
       var methods = baseType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Static); 
       foreach (var mi in methods) 
        if (mi.Name == methodInfo.Name) 
        { 
         var miParams = mi.GetParameters(); 
         var methodInfoParams = methodInfo.GetParameters(); 
         if (miParams.Length == methodInfoParams.Length) 
         { 
          var i = 0; 
          for (; i < miParams.Length; i++) 
          { 
           if (miParams[i].ParameterType != methodInfoParams[i].ParameterType 
            || ((miParams[i].Attributes^methodInfoParams[i].Attributes).HasFlag(ParameterAttributes.Out))) break; 

           // Simplified from: 
           //if (miParams[i].ParameterType != methodInfoParams[i].ParameterType 
           // || (miParams[i].Attributes.HasFlag(ParameterAttributes.Out) && !methodInfoParams[i].Attributes.HasFlag(ParameterAttributes.Out)) 
           // || !(miParams[i].Attributes.HasFlag(ParameterAttributes.Out) && methodInfoParams[i].Attributes.HasFlag(ParameterAttributes.Out))) break; 
          } 
          if (i == miParams.Length) 
          { 
           hiddenBaseMethodInfo = mi; 
           break; 
          } 
         } 
        } 
       if (hiddenBaseMethodInfo != null && !hiddenBaseMethodInfo.IsPrivate) return true; 
      } 
     } 
     return false; 
    } 

我測試它使用簡單的繼承,它的工作原理。我不考慮泛型方法..是..


編輯:我只是改變上面的代碼,因爲我忘了繼承類型可以包含這是不應該threated新新聲明的方法的想法。 IsHiding()將首先確保它具有相同的​​(它看起來像新的),但需要看底座由DeclaringType.BaseType聲明類型,如果使用相同的名稱的方法存在。

請注意,由於沒有BindingFlags.DeclaredOnly,GetMethod()會搜索整個基類型,所以不需要遞歸搜索到每個基類型。 BindingFlags.FlattenHierarchy用於包括像這樣的抽象抽象基類的靜態方法:

public abstract class A 
{ 
    public static void Stat() { } 
} 
public abstract class B : A 
{ 
} 
public class C: B 
{ 
    public new static void Stat() { } 
} 

EDIT:剛纔修正以上IsHiding()檢查重載基方法和防止AmbiguousMatchException通過使用GetMethods()而不是GetMethod()。測試了具有不同參數的組合工作重載,拌入refoutparams和可選參數。用於重載簽名基於參數計數,參數類型和它的改性劑進行比較:

  • refout包含在簽名但兩者不能被重載到彼此。在最右邊的參數
  • 返回類型,可選(默認值)和params應該

ref相比可以忽略不計由ParameterType本身(見調試期間,結束「&」),並沒有必要由IsByRef比較而out則由Attributes旗標比較。當且僅當其中一個屬性標記爲Out時,我使用簡化表達式按位異或來跳過循環,從而使簽名不同。與HasFlag在.NET 4,不要混淆,它只是想確保Out位爲1的XOR結果。

+0

你可能已經做了人這個工作沒什麼....類'MethodBase'具有以下屬性:'IsHideBySig',這幾乎不正是你的'IsHiding'方法所做的:P SRY:P – JBSnorro 2011-07-06 15:19:09

+0

真的嗎?我只是忽略它,因爲名字混亂。應該是'IsHideBySignature'。忘記「IsHiding」是因爲如果方法名稱有重載,它會拋出'AmbiguousMatchException'。我將使用'IsHideBySig'。 – CallMeLaNN 2011-07-07 01:32:49

+0

'IsHideBySig'似乎不能完全符合我的想法。它會一直返回'true'。似乎並不代表「新」關鍵字。 MSDN http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.ishidebysig.aspx聲稱它會返回true與C#'new'修飾符聲明的成員上,但它也返回TRUE;對所有其他情況像'override',新聲明的方法和extern! – CallMeLaNN 2011-07-07 02:57:57

相關問題