反射与显式实现接口的方法

在[url=http://rednaxelafx.iteye.com/blog/391600]前一帖[/url]里,我用到了下面三处Expression.Call()的调用。它们都需要一个MethodInfo参数来指定调用的方法,我就通过直观的反射来得到这些参数。
// 1
Expression.Call(
Expression.Constant(list),
typeof(IEnumerable<int>).GetMethod("GetEnumerator"))

// 2
Expression.Call(
vIter,
typeof(IEnumerator).GetMethod("MoveNext"))

// 3
Expression.Call(
typeof(Console).GetMethod("WriteLine", new[] { typeof(int) }),
new[] { vI })

其中,在注释1的地方我要实现的是list.GetEnumerator()的效果,list是一个IOrderedEnumerable<int>类型的变量;
在注释2的地方我要实现的是iter.MoveNext(),iter是一个IEnumerator<int>类型的变量,由ParameterExpression类型的vIter提供。

要是把这两处代码改一下,变成这样:
// 1
Expression.Call(
Expression.Constant(list),
list.GetType().GetMethod("GetEnumerator"))

// 2
Expression.Call(
vIter,
vIter.Type.GetMethod("MoveNext"))

也就是获取变量的类型然后对其做反射来查找方法,就会……在运行时得到NullReferenceException。为什么?

仔细观察可以留意到,IOrderedEnumerable<T>中GetEnumerator()方法是显式实现IEnumerable<T>的;IEnumerator<T>的MoveNext()是显式实现IEnumerator的。
在C#中,如果显式实现一个接口,那么显式实现的方法就会被标记为私有的。Type.GetMethod()方法默认只寻找公有成员,于是就出错了。
C#语言规范里有这么一段:
[quote="C# Language Specification"]Explicit interface member implementations have different accessibility characteristics than other members. Because explicit interface member implementations are never accessible through their fully qualified name in a method invocation or a property access, they are in a sense private. However, since they can be accessed through an interface instance, they are in a sense also public.[/quote]
总之要用反射找这样的显式实现接口的方法,在GetMethod()的时候记得带上BindingFlags.NonPublic没错的~

P.S. CLI里并没有“显式实现接口”的概念,只有mapped和implicit实现的区别。这里提到的显式实现接口是C#语言的规则而已。

P.P.S Chris Brumme以前写过一帖详细描述了显式实现接口生成的代码,[url=http://blogs.msdn.com/cbrumme/archive/2003/05/03/51381.aspx]Interface Layout[/url]。CLR要理解C#的显式接口实现,关键在于显式实现接口方法的方法体里的.override信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值