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

前一帖里,我用到了下面三处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#语言规范里有这么一段:
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.

总之要用反射找这样的显式实现接口的方法,在GetMethod()的时候记得带上BindingFlags.NonPublic没错的~

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

P.P.S Chris Brumme以前写过一帖详细描述了显式实现接口生成的代码, Interface Layout。CLR要理解C#的显式接口实现,关键在于显式实现接口方法的方法体里的.override信息。

你可能感兴趣的:(C++,c,C#,Blog,Access)