通常,我会像这样访问一个反射方法:
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
}
}
如何使用反射访问显式实现的方法?
答案 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);