使用表达式树访问对象、类型及成员(上):获取类型和成员的信息
当我们要打印一个字段或属性的值时,通常会采用如下的方法:
public class SomeClass { public string SomeField = "Some Field value"; } SomeClass someClass = new SomeClass(); Console.WriteLine("Some Field :" + someClass.SomeField);
对于这种硬编码的坏处自然不言而喻,拼写错误等等是小事,一旦名称更改,四处查找替换无异于一场灾难。也许我们可以通过一个静态字段来代替硬编码,但如果要打印的字段过多,逐一添加静态字段也是相当痛苦的事情。
对此我们可以使用表达式树来解决:
public static string GetName<T>(Expression<Func<T>> expr) { var member = expr.Body as MemberExpression; if (member != null) return member.Member.Name; throw new ArgumentException( "'" + expr + "': is not a valid expression for this method"); }
SomeClass someClass = new SomeClass(); Console.WriteLine("{0} : {1}", GetName(() => someClass.SomeField), someClass.SomeField);
表达式树给我们带来了智能感知和编译时语法错误提示,即使更改了字段或属性名称,也可以使用重构工具快速修复代码。
但是,在获取类型成员的数据时,我们还是会不可避免地使用硬编码字符串。我们可以使用typeof关键字来获取一个对象的类型而不必使用硬编码字符串,但是C#却没有提供相应的memberof。我们只能使用GetField或GetMethod等反射方法,将代表字段或方法名称的字符串作为参数传递进去。
Type type = typeof(SomeClass); MethodInfo method = type.GetMethod("SomeMethod");
如果SomeMethod方法包含重载方法,我们还不得不指定其参数。
Type type = typeof(SomeClass); MethodInfo method = type.GetMethod("SomeMethod", new Type[] { typeof(String) });
这样的API使用起来实在是太不方便了。不但要使用无法在编译时检查的硬编码字符串,参数的个数、类型等等还会因为方法签名的修改而大受牵连。
好吧,让我们用表达式树来改变这一切。
public static MemberInfo MemberOf<T>(Expression<Func<T>> e) { return MemberOf(e.Body); } // We need to add this overload to cover scenarios // when a method has a void return type. public static MemberInfo MemberOf(Expression<Action> e) { return MemberOf(e.Body); } private static MemberInfo MemberOf(Expression body) { var member = body as MemberExpression; if (member != null) return member.Member; var method = body as MethodCallExpression; if (method != null) return method.Method; throw new ArgumentException( "'" + body + "': not a member access"); }
这样,我们就可以像调用方法一样来获取MemberInfo了。
Console.WriteLine(MemberOf(() => someClass.SomeField)); // Prints System.String SomeField // To choose a particular method overload, // you simply show the usage of the method. Console.WriteLine(MemberOf(() => someClass.SomeMethod("Test"))); // Prints Void SomeMethod(System.String) Console.WriteLine(MemberOf(() => someClass.SomeMethod())); // Prints Void SomeMethod() Console.WriteLine(MemberOf(() => Console.Out)); // Prints System.IO.TextWriter Out
参考:
Getting Information About Objects, Types, and Members with Expression Trees
分类:
[02] 语言编程
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架