在[url=http://rednaxelafx.iteye.com/blog/391600]前一帖[/url]里,我用到了下面三处Expression.Call()的调用。它们都需要一个MethodInfo参数来指定调用的方法,我就通过直观的反射来得到这些参数。
其中,在注释1的地方我要实现的是list.GetEnumerator()的效果,list是一个IOrderedEnumerable<int>类型的变量;
在注释2的地方我要实现的是iter.MoveNext(),iter是一个IEnumerator<int>类型的变量,由ParameterExpression类型的vIter提供。
要是把这两处代码改一下,变成这样:
也就是获取变量的类型然后对其做反射来查找方法,就会……在运行时得到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信息。
// 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信息。