检测一个方法是否被reflection(C#)覆盖

假设我有一个基类TestBase,我定义了一个虚方法TestMe()

class TestBase { public virtual bool TestMe() { } } 

现在我inheritance这个类:

 class Test1 : TestBase { public override bool TestMe() {} } 

现在,使用reflection,我需要find如果方法TestMe已被覆盖子类 – 是否有可能?

我所需要的 – 我正在编写一个types为“object”的devise器可视化工具来显示inheritance的整个层次结构,并显示哪个虚拟方法在哪个级别被覆盖。

给定typesTest1 ,你可以确定它是否有自己的TestMe实现声明:

 typeof(Test1).GetMethod("TestMe").DeclaringType == typeof(Test1) 

如果声明来自基本types,则将评估为false。

请注意,由于这是testing声明,而不是真正的实现,所以如果Test1也是抽象的而TestMe是抽象的,那么它将返回true,因为Test1会有自己的声明。 如果你想排除这种情况,添加&& !GetMethod("TestMe").IsAbstract

正如@CiprianBortos所指出的那样,接受的答案并不完整,如果按照原样使用,会导致代码中的恶意错误。

他的评论提供了神奇的解决schemeGetBaseDefinition() ,但是如果你想要一个通用的IsOverride检查(我认为是这个问题的关键),就methodInfo.GetBaseDefinition() != methodInfo ,只需要methodInfo.GetBaseDefinition() != methodInfo

或者,作为MethodInfo的扩展方法提供,我认为这将做的伎俩:

 public static class MethodInfoUtil { public static bool IsOverride(this MethodInfo methodInfo) { return (methodInfo.GetBaseDefinition() != methodInfo); } } 

我无法得到Ken Beckett提出的解决scheme 。 以下是我所解决的问题:

  public static bool IsOverride(MethodInfo m) { return m.GetBaseDefinition().DeclaringType != m.DeclaringType; } 

要点有testing。

一个简单的解决scheme,也将工作受保护的成员和属性如下:

 var isDerived = typeof(Test1 ).GetMember("TestMe", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly).Length == 0; 

这是我在这里的答案的重新发布,这反过来又提到了这个问题。

一种在一些不平凡的情况下也可以工作的方法:

 public bool Overrides(MethodInfo baseMethod, Type type) { if(baseMethod==null) throw new ArgumentNullException("baseMethod"); if(type==null) throw new ArgumentNullException("type"); if(!type.IsSubclassOf(baseMethod.ReflectedType)) throw new ArgumentException(string.Format("Type must be subtype of {0}",baseMethod.DeclaringType)); while(type!=baseMethod.ReflectedType) { var methods=type.GetMethods(BindingFlags.Instance| BindingFlags.DeclaredOnly| BindingFlags.Public| BindingFlags.NonPublic); if(methods.Any(m=>m.GetBaseDefinition()==baseMethod)) return true; type=type.BaseType; } return false; } 

而一些丑陋的testing:

 public bool OverridesObjectEquals(Type type) { var baseMethod=typeof(object).GetMethod("Equals", new Type[]{typeof(object)}); return Overrides(baseMethod,type); } void Main() { (OverridesObjectEquals(typeof(List<int>))==false).Dump(); (OverridesObjectEquals(typeof(string))==true).Dump(); (OverridesObjectEquals(typeof(Hider))==false).Dump(); (OverridesObjectEquals(typeof(HiderOverrider))==false).Dump(); (OverridesObjectEquals(typeof(Overrider))==true).Dump(); (OverridesObjectEquals(typeof(OverriderHider))==true).Dump(); (OverridesObjectEquals(typeof(OverriderNothing))==true).Dump(); } class Hider { public virtual new bool Equals(object o) { throw new NotSupportedException(); } } class HiderOverrider:Hider { public override bool Equals(object o) { throw new NotSupportedException(); } } class Overrider { public override bool Equals(object o) { throw new NotSupportedException(); } } class OverriderHider:Overrider { public new bool Equals(object o) { throw new NotSupportedException(); } } class OverriderNothing:Overrider { } 

根据这个答案 ,还可以有一个简单的方法来检查是否重写了一个虚拟方法,而不是使用MethodAttributes.NewSlot属性的testing来知道确切的派生或基本types:

 public static bool HasOverride(this MethodInfo method) { return (method.Attributes & MethodAttributes.Virtual) != 0 && (method.Attributes & MethodAttributes.NewSlot) == 0; } 

再加上另外一个扩展方法

 private const BindingFlags Flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; public static bool HasOverride(this Type type, string name, params Type[] argTypes) { MethodInfo method = type.GetMethod(name, Flags, null, CallingConventions.HasThis, argTypes, new ParameterModifier[0]); return method != null && method.HasOverride(); } 

你可以直接打电话

 bool hasOverride = GetType().HasOverride(nameof(MyMethod), typeof(Param1Type), typeof(Param2Type), ...); 

检查是否在派生类中重写了MyMethod

据我testing,这似乎工作正常(在我的机器上)。

有一个更好,更安全,更快的方法来做到这一点。 如果您的类实例将具有较长的寿命,并且必须执行多次IsOverridden检查,则此技术才有意义。

为了解决这个问题,我们可以使用caching和C#委托,比reflection快得多!

 // Author: Salvatore Previti - 2011. /// <summary>We need a delegate type to our method to make this technique works.</summary> delegate int MyMethodDelegate(string parameter); /// <summary>An enum used to mark cache status for IsOverridden.</summary> enum OverriddenCacheStatus { Unknown, NotOverridden, Overridden } public class MyClassBase { /// <summary>Cache for IsMyMethodOverridden.</summary> private volatile OverriddenCacheStatus pMyMethodOverridden; public MyClassBase() { // Look mom, no overhead in the constructor! } /// <summary> /// Returns true if method MyMethod is overridden; False if not. /// We have an overhead the first time this function is called, but the /// overhead is a lot less than using reflection alone. After the first time /// this function is called, the operation is really fast! Yeah! /// This technique works better if IsMyMethodOverridden() should /// be called several times on the same object. /// </summary> public bool IsMyMethodOverridden() { OverriddenCacheStatus v = this.pMyMethodOverridden; switch (v) { case OverriddenCacheStatus.NotOverridden: return false; // Value is cached! Faaast! case OverriddenCacheStatus.Overridden: return true; // Value is cached! Faaast! } // We must rebuild cache. // We use a delegate: also if this operation allocates a temporary object // it is a lot faster than using reflection! // Due to "limitations" in C# compiler, we need the type of the delegate! MyMethodDelegate md = this.MyMethod; if (md.Method.DeclaringType == typeof(MyClassBase)) { this.pMyMethodOverridden = OverriddenCacheStatus.NotOverridden; return false; } this.pMyMethodOverridden = OverriddenCacheStatus.Overridden; return true; } /// <summary>Our overridable method. Can be any kind of visibility.</summary> protected virtual int MyMethod(string parameter) { // Default implementation return 1980; } /// <summary>Demo function that calls our method and print some stuff.</summary> public void DemoMethod() { Console.WriteLine(this.GetType().Name + " result:" + this.MyMethod("x") + " overridden:" + this.IsMyMethodOverridden()); } } public class ClassSecond : MyClassBase { } public class COverridden : MyClassBase { protected override int MyMethod(string parameter) { return 2011; } } class Program { static void Main(string[] args) { MyClassBase a = new MyClassBase(); a.DemoMethod(); a = new ClassSecond(); a.DemoMethod(); a = new COverridden(); a.DemoMethod(); Console.ReadLine(); } } 

当您作为控制台应用程序运行此程序时,它将打印:

 MyClassBase result:1980 overridden:False ClassSecond result:1980 overridden:False COverridden result:2011 overridden:True 

使用Visual Studio 2010,C#4.0进行testing。 还应该在以前的版本上工作,但是由于在新版本中对委托进行了优化,所以在C#上可能会稍微慢一点,但是对于这个问题的testing将不胜感激:)但是它会比使用reflection更快!