11

通常,我在反射中访问一个方法,如下所示:

class Foo
{
    public void M () {
        var m = this.GetType ().GetMethod ("M");
        m.Invoke(this, new object[] {}); // notice the pun
    }
}

但是,当 M 是显式实现时,这会失败:

class Foo : SomeBase
{
    void SomeBase.M () {
        var m = this.GetType ().GetMethod ("M");
        m.Invoke(this, new object[] {}); // fails as m is null
    }
}

如何使用反射访问显式实现的方法?

4

2 回答 2

15

It's because the name of the method is not "M", it will be "YourNamespace.SomeBase.M". So either you will need to specify that name (along with appropriate BindingFlags), or get the method from the interface type instead.

So given the following structure:

namespace SampleApp
{    
    interface IFoo
    {
        void M();
    }

    class Foo : IFoo
    {
        void IFoo.M()
        {
            Console.WriteLine("M");
        }
    }
}

...you can do either this:

Foo obj = new Foo();
obj.GetType()
    .GetMethod("SampleApp.IFoo.M", BindingFlags.Instance | BindingFlags.NonPublic)
    .Invoke(obj, null);            

...or this:

Foo obj = new Foo();
typeof(IFoo)
    .GetMethod("M")
    .Invoke(obj, null);  
于 2010-09-06T10:16:04.500 回答
3

您根本不能依赖实现类上的方法名称——它可以是任何东西。到目前为止,C# 编译器使用的惯例是在方法名称前加上接口的全名,但这是一个内部实现细节,对于例如 F# 也不适用。正确的方法是使用InterfaceMapping如果你想要一个MethodInfo实现。

例如,如果我们有以下结构

namespace LibBar
{
  [AttributeUsage(AttributeTargets.Method)]
  public class AnswerAttribute : Attribute { }

  public interface IFoo
  {
    void Hello();
    int GetAnswer();
    object WhoAmI();
  }
}

在 F# 项目中

namespace LibFoo
open LibBar

type Foo() = 
    interface IFoo with
        [<Answer>]
        member this.GetAnswer() = 42
        member this.Hello() = printf "Hello, World!"
        member this.WhoAmI() = this :> obj

如果我们只想通过反射调用,那么获取接口GetAnswer()就足够了MethodInfo

Foo obj = new Foo();
int answer = (int)typeof(IFoo)
  .GetMethod("GetAnswer")
  .Invoke(obj, null);

但是说我们想看看实现是否有AnswerAttribute。那么仅仅MethodInfo在接口上有 for 方法是不够的。如果这是 C#,方法的名称将是"LibBar.IFoo.GetAnswer",但我们希望它独立于编译器和使用的语言中的实现细节而工作。

private static MethodInfo GetMethodImplementation(Type implementationType, MethodInfo ifaceMethod)
{
  InterfaceMapping ifaceMap = implementationType.GetInterfaceMap(ifaceMethod.DeclaringType);
  for (int i = 0; i < ifaceMap.InterfaceMethods.Length; i++)
  {
    if (ifaceMap.InterfaceMethods[i].Equals(ifaceMethod))
      return ifaceMap.TargetMethods[i];
  }
  throw new Exception("Method missing from interface mapping??"); // We shouldn't get here
}

...

  Foo obj = new Foo();
  MethodInfo ifaceMethod = typeof(IFoo).GetMethod("GetAnswer");
  MethodInfo implementationMethod = GetMethodImplementation(typeof(Foo), ifaceMethod);
  Console.WriteLine("GetAnswer(): {0}, has AnswerAttribute: {1}",
    implementationMethod.Invoke(obj, null),
    implementationMethod.GetCustomAttribute<AnswerAttribute>() != null);
于 2018-10-10T15:11:55.190 回答