今天无意中看到这一篇文章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 });
输出结果为:
使用强类型反射的好处是编译器检查,如果方法签名不匹配就会报错,避免了运行时抛出异常。当然它也有不足,不同的方法签名对应一个相应签名的delegate,而且这样的实现效率很低,因为使用了表达式树等,只能根据需要进行取舍了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?