简体   繁体   中英

Reflection: How to get base method (not original method)?

class A {
    public virtual void Func() { }
}

class B : A {
    public override void Func() => base.Func();
}

class C : B {
    public override void Func() => base.Func();
}


var type = typeof( C );
var method = type.GetMethod( "Func" );
method.GetBaseDefinition().DeclaringType.Name // A
method.GetRuntimeBaseDefinition().DeclaringType.Name // A

GetBaseDefinition returns method of A class. But I need method of B class.

Is it possible?

There's an inheritance relationship between A , B , and C . But there's no such relationship between methods in the various classes. C isn't overriding a method in B - it's overriding a method in A . That's why the method won't give you any base definition other than the one where it was first declared.

MethodInfo.GetBaseDefinition

... returns the MethodInfo object for the method on the direct or indirect base class in which the method represented by this instance was first declared .

If you want to find the implementation of that method that is used in C 's immediate base class (whether or not it is declared there or inherited) then you would find out what that type is and look for the method there.

var type = typeof(C);
var baseType = type.BaseType;
var method = baseType.GetMethod("Func");

If a method is found, it isn't necessarily declared in B . Nothing says that B must have that method. If it doesn't the above will return the method from A .

If you want only what's declared in B then you would do this:

var method = baseType.GetMethod("Func", 
    BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);

DeclaredOnly means that it must be declared in B , not inherited by B .

Now you'll get the method from B if there is one, or null if it's not overridden in B .

Walking inheritance tree

You could use some reflection and walk inheritence tree of given type, type by type:

public static Type GetMethodDeclaringTypeClosestInHierarchy(MethodInfo derivedTypeMethod)
{
    //Method is not virtual, you have the only definition in inheritance tree
    if (!derivedTypeMethod.IsVirtual) return derivedTypeMethod.DeclaringType;

    var baseType = derivedTypeMethod.DeclaringType.BaseType;

    while (baseType != null)
    {
        //Check if in base type there is a method
        if (baseType.GetMethods().Any(baseTypeMethod =>
            //that has same base definition like then one we're checking
            baseTypeMethod.GetBaseDefinition() == derivedTypeMethod.GetBaseDefinition()
            //and is actually overriden in baseType
            && baseTypeMethod.DeclaringType == baseType))
        {

            return baseType;
        }
        //If not, go on higher in inheritance tree
        baseType = baseType.BaseType;
    }

    //Found nothing
    return derivedTypeMethod.DeclaringType;
}

Ambiguous method name

Problem with Scott's answer is that when you have two methods with different signatures but same name in inheritance tree:

class A
{
    public virtual void Func() { }
    public virtual string Func(string test) { return ""; }
}

class B : A
{
    public override string Func(string test) => base.Func(test);
    public override void Func() => base.Func();
}

class C : B
{
    public override void Func() => base.Func();
}

you will get an System.Reflection.AmbiguousMatchException: 'Ambiguous match found.' on

typeof(B).GetMethod("Func",
                BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);

Usage

static void Main(string[] args)
{
    var type = typeof(C);

    //This will throw with multiple methods of given name:
    var method1 = type.GetMethod("Func");

    //This will not but you need to be pretty explicit on what you're searching for
    var method2 = type.GetMethods().SingleOrDefault(m => m.Name == "Func" && m.ReturnType == typeof(void));

    var result = GetMethodDeclaringTypeClosestInHierarchy(method2);
    Console.WriteLine(result);

    Console.ReadKey();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM