C#如何使用表达式树动态更新类的属性值
发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,本篇内容介绍了"C#如何使用表达式树动态更新类的属性值"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
千家信息网最后更新 2025年11月07日C#如何使用表达式树动态更新类的属性值
本篇内容介绍了"C#如何使用表达式树动态更新类的属性值"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
C#的λ表达式树是一个好东西,也是别的语言学不来的,熟悉掌握λ表达式就能够实现各种场景的个性化操作,如动态拼接查询条件、排序方式等,也能够实现替代反射的高性能操作,比如我们常用到的IQueryable和IEnumerable,每个扩展方法就全是λ表达式树。
本文给大家分享C#使用表达式树(LambdaExpression)动态更新类的属性值的相关知识,在某些业务中会遇到需要同步两个类的属性值的情况,而且有些字段是要过滤掉的。如果手动赋值则需要写很多重复的代码:
public class Teacher { public Guid Id { get; set; } public string Name { get; set; } public string Age { get; set; } } public class Student { public Guid Id { get; set; } public string Name { get; set; } public string Age { get; set; } } /// /// 比如需要把teacher的某些属性值赋给student,而id不需要赋值 /// /// /// public static void SetProperty(Student student, Teacher teacher) { if (student.Name != teacher.Name) { student.Name = teacher.Name; } if (student.Age != teacher.Age) { student.Age = teacher.Age; } }使用反射的话性能考虑,尝试写一个扩展方法使用lambda表达式树去构建一个方法
public static class ObjectExtensions { /// /// 缓存表达式 /// /// /// public static class MapperAccessor { private static Action func { get; set; } public static TSource Set(TSource source, TTarget target, params string[] properties) { if (func == null) { var sourceType = typeof(TSource); var targetType = typeof(TTarget); BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public; if (properties.Length == 0) { //get all properties if (sourceType == targetType) { //如果是相同类型则获取所有属性 properties = sourceType.GetProperties(bindingFlags).Select(x => x.Name) .ToArray(); } else { //如果没有传指定的属性则默认获取同名属性 List propertyInfos = new List(); foreach (var property in sourceType.GetProperties(bindingFlags)) {//不同类型指定同名且类型相同的属性 var targetProperty = targetType.GetProperty(property.Name, bindingFlags); if (targetProperty != null && targetProperty.PropertyType == property.PropertyType) { propertyInfos.Add(property); } } properties = propertyInfos.Select(x => x.Name).ToArray(); } } //定义lambda 3个参数 var s = Expression.Parameter(typeof(TSource), "s"); var t = Expression.Parameter(typeof(TTarget), "t"); var ps = Expression.Parameter(typeof(string[]), "ps"); //获取泛型扩展方法Contains var methodInfo = typeof(Enumerable).GetMethods().FirstOrDefault(e => e.Name == "Contains" && e.GetParameters().Length == 2); if (methodInfo == null) { // properties.Contains() throw new NullReferenceException(nameof(methodInfo)); } MethodInfo genericMethod = methodInfo.MakeGenericMethod(typeof(String));//创建泛型方法 List bs = new List(); foreach (string field in properties) { //获取两个类型里面的属性 var sourceField = Expression.Property(s, field); var targetField = Expression.Property(t, field); //创建一个条件表达式 var notEqual = Expression.NotEqual(sourceField, targetField);//sourceField!=targetField var method = Expression.Call(null, genericMethod, ps, Expression.Constant(field));//ps.Contains(f); //构建赋值语句 var ifTrue = Expression.Assign(sourceField, targetField); //拼接表达式 sourceField!=targetField&&ps.Contains(f) var condition = Expression.And(notEqual, Expression.IsTrue(method)); //判断是否相同,如果不相同则赋值 var expression = Expression.IfThen(condition, ifTrue); bs.Add(Expression.Block(expression)); } var lambda = Expression.Lambda>(Expression.Block(bs), s, t, ps); func = lambda.Compile(); } func.Invoke(source, target, properties); return source; } } /// /// 通过目标类更新源类同名属性值 /// /// 待更新的数据类型 /// 目标数据类型 /// 源数据 /// 目标数据 /// 要变更的属性名称 /// 返回源数据,更新后的 public static TSource SetProperties(this TSource source, TTarget target, params string[] properties) { return MapperAccessor.Set(source, target, properties); } } 编写测试方法
////// 比如需要把teacher的某些属性值赋给student,而id不需要赋值 /// /// /// public static void SetProperty(Student student, Teacher teacher) { if (student.Name != teacher.Name) { student.Name = teacher.Name; } if (student.Age != teacher.Age) { student.Age = teacher.Age; } } public static void SetProperty2(Student student, Teacher teacher, params string[] properties) { var sourceType = student.GetType(); var targetType = teacher.GetType(); foreach (var property in properties) { var aP = sourceType.GetProperty(property); var bP = targetType.GetProperty(property); var apValue = aP.GetValue(student); var bpValue = bP.GetValue(teacher); if (apValue != bpValue) { aP.SetValue(student, bpValue); } } } static (List, List ) CreateData(int length) { var rd = new Random(); (List , List ) ret; ret.Item1 = new List (); ret.Item2 = new List (); for (int i = 0; i < length; i++) { Student student = new Student() { Id = Guid.NewGuid(), Name = Guid.NewGuid().ToString("N"), Age = rd.Next(1, 100) }; ret.Item1.Add(student); Teacher teacher = new Teacher() { Id = Guid.NewGuid(), Name = Guid.NewGuid().ToString("N"), Age = rd.Next(1, 100) }; ret.Item2.Add(teacher); } return ret; } static void Main(string[] args) { var length = 1000000; var data = CreateData(length); Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 0; i < length; i++) { SetProperty(data.Item1[i], data.Item2[i]); } sw.Stop(); Console.WriteLine($"手写方法耗时:{sw.ElapsedMilliseconds}ms"); data.Item1.Clear(); data.Item2.Clear(); var data2 = CreateData(length); sw.Restart(); for (int i = 0; i < length; i++) { data2.Item1[i].SetProperties(data2.Item2[i], nameof(Student.Age), nameof(Student.Name)); } data2.Item1.Clear(); data2.Item2.Clear(); sw.Stop(); Console.WriteLine($"lambda耗时:{sw.ElapsedMilliseconds}ms"); var data3 = CreateData(length); sw.Restart(); for (int i = 0; i < length; i++) { SetProperty2(data3.Item1[i], data3.Item2[i], nameof(Student.Age), nameof(Student.Name)); } sw.Stop(); Console.WriteLine($"反射耗时:{sw.ElapsedMilliseconds}ms"); data3.Item1.Clear(); data3.Item2.Clear(); Console.ReadKey(); }

可以看到性能和手写方法之间的差距,如果要求比较高还是手写方法,如果字段多的话写起来是很痛苦的事。但是日常用这个足够了,而且是扩展方法,通用性很强。
"C#如何使用表达式树动态更新类的属性值"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!
属性
表达式
方法
更新
类型
数据
动态
C#
相同
目标
知识
反射
两个
内容
字段
性能
情况
更多
条件
不同
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
铁路网络安全十严禁
达芬奇怎么删除建立的数据库
网络安全不需要变革
bim 软件开发
小鹅网络技术有限公司
1.2t服务器硬盘
数据库具有的特点
北京网络安全培训怎么样
电子表格带数据库
webex服务器国内
保存与服务器
客户端与服务器通信格式
安卓app软件开发企业
工控系统网络安全机制
数据库明年还考吗
广州极优网络技术
在财经网怎么查数据库
专家解读《网络安全法
智慧称重软件开发商
大唐集团总部网络安全态势
数据库选择运算表示方法
bat服务器
什么网络安全培训机构最好
软件开发实习的实习心得
战地4租用服务器多少钱
深圳视频软件开发
服务器分类
网络安全法治日宣传
常州idc服务器厂家直供
qt密码数据库不安全