Detect if a method was overridden using Reflection (C#)
Asked Answered
J

9

70

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.

Junno answered 28/5, 2010 at 20:47 Comment(1)
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.Jolandajolanta
F
78

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

Fanchette answered 28/5, 2010 at 20:51 Comment(4)
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.Oops
@Ciprian this isn't a complete code solution, just explaining where to find the relevant parts of reflection to pull if off.Fanchette
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.Thickness
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()Expansionism
K
40

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.

Kileykilgore answered 13/5, 2013 at 20:56 Comment(5)
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.Beak
@DimitriC.I am using Assembly.Load([myAssembleyNameHere]).GetTypes() and it's working perfectly fine.. should be marked as accepted solution.Pharmacology
@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...Alkalize
...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.Alkalize
Works like a charm. This should be the accepted answer.Prowess
O
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);
    }
}
Othello answered 4/4, 2012 at 23:59 Comment(4)
This implementation returns true for inherited methods -- see NUnit test gist. m.GetBaseDefinition().DeclaringType != m.DeclaringType works better.Kileykilgore
code has a syntax error, what is "this" keyword representing?Pharmacology
MethodInfo could be different if ReflectedType is different.Tissue
@Pharmacology this is part of the signature that makes the IsOverride method a static method.Randle
S
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.

Spenser answered 30/8, 2011 at 0:4 Comment(0)
T
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
{

}
Thickness answered 27/2, 2012 at 14:47 Comment(0)
S
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™).

Sialkot answered 1/5, 2016 at 22:12 Comment(3)
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.Alkalize
@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.Sialkot
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.Alkalize
C
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!

Cloudcapped answered 13/8, 2011 at 20:5 Comment(2)
Your caching strategy is quite suboptimal. I'd rather use a static dictionary, so you can get a general helper method. ConditionalWeakTable<Type,Dictionary<MethodInfo,bool>> seems like a good choice. And of course it's broken in the same way as Rex's answer.Thickness
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.Cloudcapped
T
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();
    }
Tissue answered 8/5, 2019 at 11:46 Comment(0)
H
0

Simple 1-liner based on this and this answers:

typeof(T).GetMember(nameof("Method")).OfType<MethodInfo>()
                .Where(m => m.GetBaseDefinition().DeclaringType != m.DeclaringType);
Hahn answered 31/8, 2022 at 12:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.