使用Linq实现强类型反射

  今天无意中看到这一篇文章Linq beyond queries: strong-typed reflection,发现Linq除了查询还可以用于其它方面,这篇文章里面主要介绍了如何通过Linq来实现强类型的反射。

  通常在使用反射的时候,如果不小心把方法名称写错或者参数类型不匹配,运行时就会抛出异常。一般来说我们会这样写代码来获得MethodInfo:

 MethodInfo mi = typeof(MyTest).GetMethod("TestFunc",new Type[]{ typeof(string), typeof(int)});

 如果对MyTest类进行重构,改变了方法的名称或者参数类型等,运行时肯定会出现异常,因为这些错误在编译期间是检查不出来的。如果项目中大量使用了反射,无疑一点改动就会引发潜在的问题。 现在出现了Linq,通过Lambda表达式树可以实现强类型反射。下面是我仿照它的例子写的测试代码,因为现在的API有了一些改动,具体的介绍可以看原文:

 public class MyReflection
 {
     
     public delegate void Operation<T>(T declaringType);

     public delegate void Operation<T, A1, A2>(T declaringType, object a1, object a2);

     public delegate object OperationWithReturnValue<T>(T declaringType);


     public static MethodInfo Method<T>(Expression<Operation<T>> method)
     {
         return GetMethodInfo(method);
     }

     public static MethodInfo Method<T>(Expression<OperationWithReturnValue<T>> method)
     {
         return GetMethodInfo(method);
     }

     public static MethodInfo Method<T, A1, A2>(Expression<Operation<T, A1, A2>> method)
     {
         return GetMethodInfo(method);
     }

     private static MethodInfo GetMethodInfo(Expression method)
     {
         LambdaExpression lambda = method as LambdaExpression;

         if (lambda == null)
             throw new ArgumentNullException();

         MethodCallExpression methodExpr = null;

         if (lambda.Body.NodeType == ExpressionType.Call)
             methodExpr = lambda.Body as MethodCallExpression;
         else if (lambda.Body.NodeType == ExpressionType.Convert)
             methodExpr = ((UnaryExpression)lambda.Body).Operand as MethodCallExpression;

         if (methodExpr == null)
             throw new ArgumentException();

         return methodExpr.Method;
     }
 }

 首先创建了三个delegate,用来委托我们自己定义的方法。这里也可以使用Func,不过Func要求有返回值,不能委托无返回值的方法。代码很简单,有一点值得注意的是ExpressionType.Call表示无返回值的方法,ExpressionType.Convert表示有返回值的方法。

 下面是一个测试类:

 public class MyTest
 {
     public void TestFunc()
     {
         Console.WriteLine("Test Function");
     }
     public static void StaticTestFunc()
     {
         Console.WriteLine("Test Static Function");
     }

     public int TestFuncWithReturnValue()
     {
         Console.WriteLine("Test function with return value");
         return 100;
     }
     public void TestFuncWithArgs(string arg1, int arg2)
     {

         Console.WriteLine("Test function with arguments [{0},{1}]", arg1, arg2.ToString());
     }
 }

最后看看怎样使用:

 MethodInfo mi = MyReflection.Method<MyTest>(m => m.TestFunc());
 mi.Invoke(new MyTest(), null);

 mi = MyReflection.Method<MyTest>(m => MyTest.StaticTestFunc());
 mi.Invoke(null, null);

 mi = MyReflection.Method<MyTest>(m => m.TestFuncWithReturnValue());
 Console.WriteLine("Return value from TestFuncWithReturnValue is {0}", mi.Invoke(new MyTest(), null));

 mi = MyReflection.Method<MyTest, object, object>((m, x, y) => m.TestFuncWithArgs((string)x, (int)y));
 mi.Invoke(new MyTest(), new object[] { "Argument1", 50 });

 输出结果为:

image

使用强类型反射的好处是编译器检查,如果方法签名不匹配就会报错,避免了运行时抛出异常。当然它也有不足,不同的方法签名对应一个相应签名的delegate,而且这样的实现效率很低,因为使用了表达式树等,只能根据需要进行取舍了。

转载于:https://www.cnblogs.com/blusehuang/archive/2007/07/17/821053.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值