68

Say I have a base class TestBase where I define a virtual method TestMe()

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

Now I inherit this class:

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

Now, using Reflection, I need to find if the method TestMe has been overriden in child class - is it possible?

What I need it for - I am writing a designer visualizer for type "object" to show the whole hierarchy of inheritance and also show which virtual methods were overridden at which level.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
Andrey
  • 20,487
  • 26
  • 108
  • 176
  • I don't know exactly how, but something like this must be possible. There's an excellent tool called "RedGate Reflector" that will show the logic of a method in a library. – Vivian River May 28 '10 at 20:53

9 Answers9

77

Given the type Test1, you can determine whether it has its own implementation declaration of TestMe:

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

If the declaration came from a base type, this will evaluate false.

Note that since this is testing declaration, not true implementation, this will return true if Test1 is also abstract and TestMe is abstract, since Test1 would have its own declaration. If you want to exclude that case, add && !GetMethod("TestMe").IsAbstract

Rex M
  • 142,167
  • 33
  • 283
  • 313
  • 25
    This solution is not complete. It does not cover the case in which Test1 declares a method with the same name but different parameters. If the test above evaluates to true you only know that Test1 has a method with TestMe name but you do not know if it is an override. You need to also use the GetBaseDefinition() method. If this call returns a MethodInfo object that has the DeclaringType == typeof(TestBase), only then you can know for sure you have an override. – Ciprian Bortos May 08 '11 at 04:43
  • 2
    @Ciprian this isn't a complete code solution, just explaining where to find the relevant parts of reflection to pull if off. – Rex M May 08 '11 at 16:02
  • 4
    Yes I did, it's incorrect/very limited, and going from your code to a working solution is quite a bit of work. You did not even mention essential APIs like `GetBaseDefinition()`, and issues related to method hiding or differing method signatures. – CodesInChaos Feb 27 '12 at 15:07
  • 1
    If you want to check in a abstract base class if a derived class overrides a method you can do this check with this.GetType like: this.GetType().GetMethod("MethodName").DeclaringType == this.GetType() – Justin Nov 01 '13 at 11:03
39

I was unable to get Ken Beckett's proposed solution to work. Here's what I settled on:

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

There are tests in the gist.

Community
  • 1
  • 1
ESV
  • 7,620
  • 4
  • 39
  • 29
  • 2
    Works like a charm. Thanks a lot! Just a remark about getting the MethodInfo instance. I first made the mistake to get it through: `typeof(SomeType).GetMethod(someFunctionName)` With this MethodInfo instance IsOverride doesn't work. You need to do this instead: `someTypeInstance.GetType().GetMethod(someFunctionName)` This is perfectly logical of course, but still somewhat subtle. Apparently, when calling GetType(), a reference to the instance is kept in the Type object that is returned. – Dimitri C. Apr 20 '17 at 14:07
  • @DimitriC.I am using Assembly.Load([myAssembleyNameHere]).GetTypes() and it's working perfectly fine.. should be marked as accepted solution. – AZ_ May 23 '18 at 07:38
  • @DimitriC. No, in the technique shown here, no reference to the instance is in any way "kept in the `Type` object that's returned;" in fact it's exactly the other way around: every runtime *instance* knows its actual `Type`, which you can obtain via `GetType()` (To be precise, the `Type` of a type instance at runtime is `RuntimeType`, a type derived from `Type`). The good news is, despite the minor snafu in your explanation, the code you provided is technically the only way to get truly 100% correct behavior, so it's one of the most important gems on this page... – Glenn Slayden Feb 12 '19 at 00:51
  • ...Because most of the examples on this page consider static typing only, e.g. `typeof(SomeType)`, they will therefore fail for any/all instance of a `SomeType`-derived class that indeed overrides the method, even though `SomeType` might not. Since any `SomeType`-derived instance is presumably entitled to show up, you need to independently check each runtime instance via `GetType()` on every call. Not doing so is probably what caused the problem you mentioned seeing initially. – Glenn Slayden Feb 12 '19 at 00:52
  • Works like a charm. This should be the accepted answer. – Arshia001 May 13 '19 at 08:56
28

As @CiprianBortos pointed out, the accepted answer is not complete and will lead to a nasty bug in your code if you use it as-is.

His comment provides the magic solution GetBaseDefinition(), but there's no need to check the DeclaringType if you want a general-purpose IsOverride check (which I think was the point of this question), just methodInfo.GetBaseDefinition() != methodInfo.

Or, provided as an extension method on MethodInfo, I think this will do the trick:

public static class MethodInfoUtil
{
    public static bool IsOverride(this MethodInfo methodInfo)
    {
        return (methodInfo.GetBaseDefinition() != methodInfo);
    }
}
Pondidum
  • 11,457
  • 8
  • 50
  • 69
Ken Beckett
  • 1,273
  • 11
  • 13
  • 7
    This implementation returns true for inherited methods -- see [NUnit test gist](https://gist.github.com/EdVinyard/5571213). `m.GetBaseDefinition().DeclaringType != m.DeclaringType` works better. – ESV May 13 '13 at 20:29
  • code has a syntax error, what is "this" keyword representing? – AZ_ May 23 '18 at 07:30
  • MethodInfo could be different if ReflectedType is different. – Denis535 Aug 12 '18 at 17:58
  • 2
    @AZ_ `this` is part of the signature that makes the `IsOverride` method a static method. – LosManos Nov 26 '18 at 20:10
6

A simple solution which will also work for protected member and properties is as follows:

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

This is a repost of my answer here, which in turn had made references to this question.

Community
  • 1
  • 1
Michael Hays
  • 6,878
  • 2
  • 21
  • 17
2

According to this answer there could also be a simple way to check if a virtual method was overridden without to know the exact derived or base type using a test for the MethodAttributes.NewSlot attribute:

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

Together with another extension method

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();
}

you could then simply call

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

to check if MyMethod is overridden in a derived class.

As far as I've tested this, it seemed to work fine (on my machine™).

Community
  • 1
  • 1
swalex
  • 3,885
  • 3
  • 28
  • 33
  • 1
    Beware here, I think you misunderstand the meaning of the `NewSlot` flag. It is ***not*** asserted for "normal" virtual/abstract methods which, by default, participate in the traditional virtual overriding mechanism. Rather, `NewSlot` refers to the (idiosyncratic?) .NET capability of selectively *cancelling* the polymorphism chain. The concept corresponding to `NewSlot` in **C#** is the `new` keyword, which can be applied to an (otherwise-)virtual method in a derived class in order to detach it, plus all its further derivations, from base method polymorphism. – Glenn Slayden Feb 12 '19 at 01:12
  • @GlennSlayden Thank you for pointing this out. As I understood the explanations in the referenced answer, the `NewSlot` flag is set (along with the `Virtual` flag) for both base virtual methods and methods hiding an implementation in a base class, because in both of these cases the methods will get a new slot in the vtable of the class. On the other hand an override method will not get a new slot in the vtable and thus have only the `Virtual` flag set. Anyway, as you've already said, the answer from ESV is actually the best and most straight-forward solution to the question here. – swalex Feb 12 '19 at 08:48
  • 1
    I stand corrected if the `NewSlot` flag is asserted on the base method as well, thanks for that. And I guess the OPs problem statement is underspecified about whether a `NewSlot` (`new` keyword in C#) derived method is supposed to be analyzed as "HasOverride" or not. – Glenn Slayden Feb 13 '19 at 00:49
2

A method that also works in some non trivial cases:

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;
}

And a few ugly tests:

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
{

}
CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
1
    public static bool HasOverridingMethod(this Type type, MethodInfo baseMethod) {
        return type.GetOverridingMethod( baseMethod ) != null;
    }
    public static MethodInfo GetOverridingMethod(this Type type, MethodInfo baseMethod) {
        var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod;
        return type.GetMethods( flags ).FirstOrDefault( i => baseMethod.IsBaseMethodOf( i ) );
    }
    private static bool IsBaseMethodOf(this MethodInfo baseMethod, MethodInfo method) {
        return baseMethod.DeclaringType != method.DeclaringType && baseMethod == method.GetBaseDefinition();
    }
Denis535
  • 3,407
  • 4
  • 25
  • 36
1

There is a better, safer and faster way to do it. This technique makes sense if your class instance is going to have a long life and the IsOverridden check must be performed several times.

To solve this problem we can use a cache and C# delegates, much faster than 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();
    }
}

When you run this program as a console application, it will print:

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

Tested with Visual Studio 2010, C# 4.0. Should work also on previous versions, but it can be a little slower on C# less than 3.0 due to optimizations to delegates in the new releases, tests about this would be appreciated :) However it will be still faster than using reflection!

Salvatore Previti
  • 8,956
  • 31
  • 37
  • Your caching strategy is quite suboptimal. I'd rather use a static dictionary, so you can get a general helper method. `ConditionalWeakTable>` seems like a good choice. And of course it's broken in the same way as Rex's answer. – CodesInChaos Feb 27 '12 at 15:11
  • Well from my point of view, is not suboptimal if you have a small number of instances and if the object have a very long life. Is subotpimal if the instance have a short life, as I said in the answer. Second, it works if you add a method with other parameters, since we are using a delegate to do the trick. Using a dictionary is not thread safe, you would need a concurrent dictionary, at least, and of course, looking in a concurrent or locked dictionary is slower than looking into a field. It all depends on the requirements actually. – Salvatore Previti Feb 28 '12 at 10:28
0

Simple 1-liner based on this and this answers:

typeof(T).GetMember(nameof("Method")).OfType<MethodInfo>()
                .Where(m => m.GetBaseDefinition().DeclaringType != m.DeclaringType);
Mr Patience
  • 1,564
  • 16
  • 30