返回顶部
首页 > 资讯 > 精选 >C#如何使用表达式树动态更新类的属性值
  • 910
分享到

C#如何使用表达式树动态更新类的属性值

2023-06-26 05:06:09 910人浏览 泡泡鱼
摘要

本篇内容介绍了“C#如何使用表达式树动态更新类的属性值”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!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; }        }   /// <summary>        /// 比如需要把teacher的某些属性值赋给student,而id不需要赋值        /// </summary>        /// <param name="student"></param>        /// <param name="teacher"></param>        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    {        /// <summary>        /// 缓存表达式        /// </summary>        /// <typeparam name="TSource"></typeparam>        /// <typeparam name="TTarget"></typeparam>        public static class MapperAccessor<TSource, TTarget>        {            private static Action<TSource, TTarget, string[]> 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<PropertyInfo> propertyInfos = new List<PropertyInfo>();                            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<BlockExpression> bs = new List<BlockExpression>();                    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<Action<TSource, TTarget, string[]>>(Expression.Block(bs), s, t, ps);                    func = lambda.Compile();                }                func.Invoke(source, target, properties);                return source;            }        }        /// <summary>        /// 通过目标类更新源类同名属性值        /// </summary>        /// <typeparam name="TSource">待更新的数据类型</typeparam>        /// <typeparam name="TTarget">目标数据类型</typeparam>        /// <param name="source">源数据</param>        /// <param name="target">目标数据</param>        /// <param name="properties">要变更的属性名称</param>        /// <returns>返回源数据,更新后的</returns>        public static TSource SetProperties<TSource, TTarget>(this TSource source, TTarget target, params string[] properties)        {            return MapperAccessor<TSource, TTarget>.Set(source, target, properties);        }    }

编写测试方法

 /// <summary>        /// 比如需要把teacher的某些属性值赋给student,而id不需要赋值        /// </summary>        /// <param name="student"></param>        /// <param name="teacher"></param>        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<Student>, List<Teacher>) CreateData(int length)        {            var rd = new Random();            (List<Student>, List<Teacher>) ret;            ret.Item1 = new List<Student>();            ret.Item2 = new List<Teacher>();            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#如何使用表达式树动态更新类的属性值”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: C#如何使用表达式树动态更新类的属性值

本文链接: https://lsjlt.com/news/306877.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C#如何使用表达式树动态更新类的属性值
    本篇内容介绍了“C#如何使用表达式树动态更新类的属性值”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!C#的&lambda;表达式树是...
    99+
    2023-06-26
  • C#使用表达式树(LambdaExpression)动态更新类的属性值(示例代码)
    有看过我之前发表过的C#相关文章分享和阅读过我代码的朋友们可能会在我的代码里面经常看到各种各样的λ表达式动态拼接,C#的λ表达式树是一个好东西,也是别的语...
    99+
    2024-04-02
  • Spring的@Scheduled 如何动态更新cron表达式
    常见的本地定时写法如下: @Scheduled(cron = "0/5 * * * * ?") private void test() { lo...
    99+
    2024-04-02
  • 如何使用JavaScript动态设置CSS3属性值
    这篇文章将为大家详细讲解有关如何使用JavaScript动态设置CSS3属性值,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。使用JavaSc...
    99+
    2024-04-02
  • C#值类型、引用类型、泛型、集合的表达式树怎么创建
    这篇文章主要介绍了C#值类型、引用类型、泛型、集合的表达式树怎么创建的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C#值类型、引用类型、泛型、集合的表达式树怎么创建文章都会有所收获,下面我们一起来看看吧。一,定...
    99+
    2023-06-26
  • C++ lambda 表达式的返回值类型如何定义?
    在 c++++ 中,lambda 表达式的返回值类型通过 ->return-type 指定,允许明确定义 lambda 的返回值。通过指定返回值类型,可以增强代码的可读性并避免编译器自动...
    99+
    2024-04-17
    c++ lambda
  • C#值类型、引用类型、泛型、集合、调用函数的表达式树实践
    目录一,定义变量二,访问变量/类型的属性字段和方法1. 访问属性调用静态类型属性调用实例属性/字段2. 调用函数调用静态类型的函数调用实例的函数三,实例化引用类型new给属性赋值创建...
    99+
    2024-04-02
  • Mybatis如何使用ognl表达式实现动态sql
    本文讲述在mybatis中如何使用ognl表达式实现动态组装sql语句 新建Users实体类: public class Users { private Integer ...
    99+
    2024-04-02
  • 如何理解CASE表达式作用及使用SQLServerCASE 表达式代替动态SQL
    本篇文章为大家展示了如何理解CASE表达式作用及使用SQLServerCASE 表达式代替动态SQL,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。  SQLServ...
    99+
    2024-04-02
  • 如何使用 C++ lambda 表达式执行延迟求值?
    如何使用 c++++ lambda 表达式执行延迟求值?使用 lambda 表达式创建延迟求值的函数对象。延迟计算推迟到需要时才执行。仅当需要时才计算结果,提高性能。 如何使用 C++...
    99+
    2024-04-17
    c++ lambda
  • C++ 如何使用栈求解中缀、后缀表达式的值
    目录1. 前言2. 中缀表达式2.1 求值流程2.2 演示表达式4*6^(3+3*3-2*3)-8 的求值过程当2.3 编码实现3.后缀表达式4. 中缀转后缀表达式4.1 流程演示4...
    99+
    2022-11-13
    C++中缀 后缀表达式的值 C++ 栈求解表达式的值
  • C++中的正则表达式如何使用
    这篇文章主要介绍了C++中的正则表达式如何使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++中的正则表达式如何使用文章都会有所收获,下面我们一起来看看吧。介绍C++ 正则表达式教程解释了 C++ 中正则表...
    99+
    2023-06-30
  • C#使用第三方组件实现动态解析和求值字符串表达式
    目录介绍1、Z.Expressions.Eval 表达式解析2、NReco.LambdaParser 表达式解析3、DynamicExpresso 表达式解析4、SQL条件语句的正则...
    99+
    2024-04-02
  • MySQL中的枚举值如何在表达式中使用?
    众所周知,枚举值与索引值相关联,因此如果我们在表达式中使用枚举值,那么所有计算都将在索引号上完成。下面的例子将阐明它 -mysql> Select * from Result; +-----+--------+-------...
    99+
    2023-10-22
  • 如何使用C++中的正则表达式函数?
    如何使用C++中的正则表达式函数?正则表达式是一种强大的文本处理工具,可以用于匹配、搜索和替换文本中的模式。在C++中,我们可以使用正则表达式函数库来实现对文本的处理。本文将介绍如何在C++中使用正则表达式函数。首先,我们需要包含C++标准...
    99+
    2023-11-18
    C++正则表达式 使用C++正则 C++正则函数
  • 在Java中如何使用groovy语言作为动态规则表达式
    小编给大家分享一下在Java中如何使用groovy语言作为动态规则表达式,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!由于在工作流设计中需要为条件分支设定条件表达...
    99+
    2023-06-17
  • HTML5如何使用新增的表单元素和属性
    这篇文章将为大家详细讲解有关HTML5如何使用新增的表单元素和属性,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。代码演示说明了HTML5新增的表单元素和属性,演示代码中包...
    99+
    2024-04-02
  • 如何使用PHP7的类常量和静态属性实现更灵活的数据管理?
    如何使用PHP7的类常量和静态属性实现更灵活的数据管理?PHP是一种广泛应用于Web开发的脚本语言,而在PHP7中,引入了许多新特性,其中包括类常量和静态属性。这两个特性在数据管理方面提供了更灵活的解决方案。本文将介绍如何使用PHP7的类常...
    99+
    2023-10-22
    PHP 静态属性 类常量
  • 如何使用更新的特性进行响应式设计
    这篇文章主要介绍“如何使用更新的特性进行响应式设计”,在日常操作中,相信很多人在如何使用更新的特性进行响应式设计问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何使用更新的特...
    99+
    2024-04-02
  • PHP8中如何使用Match表达式进行更简洁的条件判断?
    PHP8中引入了一种新的条件判断语法——Match表达式(也称为模式匹配)。在之前的版本中,我们通常使用多个if-else语句来进行条件判断,而Match表达式的出现使得这一过程更加简洁和易读。本文将介绍PHP8中如何使用Match表达式,...
    99+
    2023-10-22
    PHP Match表达式 简洁的条件判断
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作