去看更多

wangshijie
Welcome

Linq的超越——强类型反射(一)

大家都知道Linq引入了标准查询操作符,从而使查询成为C#语言中最重要的概念。但不知您是否意识到,Linq还可用于查询外的其他用途。下面我将首次探讨Linq用于查询外的其他领域。
反射问题:远离类型安全错误
至少就我自己而言使用C#这种类型安全语言时,每当按下Ctrl+Shift+BShift+F6进行编译时会有一种轻松和放心的感觉。我知道,由于使用错误的类型而产生的怪异且难于调试的运行时错误,以及像“方法缺失”这种提示几乎从未出现。但是使用反射时,如果我不小心,就会出现臭名昭著的TargetInvocationException和一些NullReferenceException之类的异常。下面正是我所遇到的
MethodInfo method =
typeof
(Mock).GetMethod("PublicMethodParameters",
    newType[]{ typeof(string), typeof(int) }));
如果对Mock类应用重构以便重命名该方法会发生什么情况呢如果参数类型发生更改会发生什么情况呢?毫无疑问,会发生运行时异常!如果采用一个使用大量反射的插入式灵活框架,这决不是一个小问题。由于害怕出错而不敢应用重构(或者使其代价昂贵)必然会限制您改进设计和完善代码的能力。那么,试着替换魔力字符串(magic strings)和松散类型的Type数组将会如何呢?
MethodInfo info =
Reflector.Method<Mock, string, int>(
(x, y, z) => x.PublicMethodParameters(y, z));
通过Linq进行强类型反射
其工作原理是作为参数传递的λ表达式就像前一版本.NET中的委托一样不一定要执行。
上面的代码基本上构造了一个可以调用类型上给定方法的λ表达式。声明方法的目标类型的类型就是Method<> static generic方法的第一个类型参数。您可指定的可选类型参数将是您要调用的方法的参数类型(如果存在)。如果我想获得无参数方法的MethodInfo,则表达式将是:
MethodInfo info = Reflector.Method<Mock>(
        x => x.PublicMethodNoParameters());
这比您以前见到的任何λ表达式都典型。在λ表达式中,如果您需要传递附加参数,则必须将所有内容放到括号中(上例中的xyz)。用于属性和字段的类型映射功能是相同的:
PropertyInfo property =
Reflector.Property<Mock>(x => x.PublicProperty);
FieldInfo field =
Reflector.Field<Mock>(x => x.PublicField);
利用表达式树
现在我们开始讨论比较有趣的内容,即如何实现它。
Linq任何接收λ表达式委托类型的方法都可以转换为接收相同委托类型的Expression<T>的方法并且不需要更改客户机代码。例如
privatestaticvoid DoSomething(Predicate<Mock> predicate)
可以替换为:
privatestaticvoid DoSomething(
   Expression<Predicate<Mock><Mock>> predicate)
在上述两种情况下调用代码可以是相同的λ表达式
DoSomething(x => x.Value > 25);
这里发生的情况是编译器不会将指针传入到第二个方法签名的匿名委托中而是生成以表达式树的形式构建AST抽象语法树IL代码。如果您打开Reflector(我的类型反射类的名字也由此而来,它是任何高级开发人员都应该经常使用的最伟大的工具)并取消对DoSomething的方法调用,就可以看到:
ParameterExpression expression1 =
    Expression.Parameter(typeof(Mock), "x");
Program.DoSomething(
Expression.Lambda<Predicate<Mock>>(

    Expression.GT(Expression.Field(
              expression1, fieldof(Mock.Value)),
    Expression.Constant(0x19, typeof(int))),
newParameterExpression[]{expression1 })
);
posted @ 2009-05-13 11:59  jeer  阅读(194)  评论(0编辑  收藏  举报