【问题标题】:How can I access an explicitly implemented method using reflection?如何使用反射访问显式实现的方法?
【发布时间】:2011-04-08 17:05:40
【问题描述】:

通常,我会像这样访问反射中的方法:

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

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

【问题讨论】:

  • 在这种情况下,M 是私有的。您应该使用BindingFlags 枚举。

标签: c# .net reflection explicit-implementation


【解决方案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);

【讨论】:

  • 感谢您提供更多信息!
【解决方案2】:

这是因为方法的名称不是"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);  

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    • 2010-09-21
    • 2019-03-05
    • 2012-09-14
    • 2023-04-10
    相关资源
    最近更新 更多