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

时间:2010-09-06 10:05:31

标签: c# .net reflection explicit-implementation

通常,我会像这样访问一个反射方法:

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

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

2 个答案:

答案 0 :(得分:9)

这是因为该方法的名称不是"M",而是"YourNamespace.SomeBase.M"。因此,您需要指定该名称(以及适当的BindingFlags),或者从接口类型中获取方法。

所以给出以下结构:

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

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

......你可以这样做:

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

......或者这个:

Foo obj = new Foo();
typeof(IFoo)
    .GetMethod("M")
    .Invoke(obj, null);  

答案 1 :(得分:1)

您完全不能依赖实现类上的方法名称-它可以是任何东西。到目前为止,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就足够了。如果该方法是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);