反思:如何获得基本方法(不是原始方法)?

时间:2019-05-18 19:43:40

标签: c# .net .net-core

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返回A类的方法。但是我需要B类的方法。

有可能吗?

2 个答案:

答案 0 :(得分:1)

步行继承树

您可以使用某些给定类型的反射和遍历继承树,按类型:

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

方法名称不明确

斯科特答案的问题是,当您在继承树中有两个签名不同但名称相同的方法时:

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

您将获得System.Reflection.AmbiguousMatchException: 'Ambiguous match found.'

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

用法

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

答案 1 :(得分:0)

ABC之间存在继承关系。但是,各个类中的方法之间没有这种关系。 C不会覆盖B中的方法,而是覆盖A中的方法。这就是为什么该方法除了最初声明的定义之外不会提供任何基本定义的原因。

MethodInfo.GetBaseDefinition

  

...返回直接或间接基类上方法的MethodInfo对象,在该基类中,首先声明此实例表示的方法。

如果您想在C的直接基类中找到该方法的实现,那么您将找出该类型是什么,然后在那里寻找该方法。

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

如果找到方法,则不一定在B中声明它。没有任何话说B必须具有该方法。如果不是,则上述方法将从A返回该方法。

如果只想<{>} B中声明的内容,则可以这样做:

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

DeclaredOnly表示必须在B中声明,而不是B继承。

现在,如果有一个方法,您将从B获取该方法;如果没有在B中重写该方法,则为null。