需求背景:对象复制性能优化;同时,在对象复制时,应跳过引用类型的null值复制,值类型支持值类型向可空类型的复制
using common;using syst撩妹回复em;class program{ static void main(string[] args) { testclassa classa = new testclassa() { propa = new testclass() { name = "cs1" }, propb = "c1", propc = 1 }; testclassa classb = new testclassa() { propa = new testclass() { name = "cs2" }, propb = "c2", propc = 2 }; fastcopy.copy(classa, classb, fal); console.writeline(classb.propa?.name + ":" + classb.propb + ":" + classb.propc); testclassa classc = new testclassa() { propa = new testclass() { name = "cs1" } }; testclassa classd = new testclassa() { propa = new testclass() { name = "cs2" }, propb = "c2", propc = 2 }; fastcopy.copy(classc, classd, fal); console.writeline(classd.propa?.name + ":" + classd.propb + ":" + classd.propc); }}public class testclassa{ public testclass propa { get; t; } public string propb { get; t; } public int? propc { get; t; }}public class testclass{ public string name { get; t; }}
输出:
百万次调用耗时:270-300ms
using system;using system.collections.concurrent;using system.collections.generic;using system.linq;using system.linq.expressions;using system.reflection;using static system.linq.expressions.expression;namespace common{ public static class fastcopy { static concurrentdictionary<string, object> copiers = new concurrentdictionary<string, object>(); /// <summary> /// 复制两个对象同名属性值 /// </summary> /// <typeparam name="s"></typeparam> /// <typeparam name="t"></typeparam> /// <param name="source">源对象</param> /// <param name="target">目标对象</param> /// <param name="copynull">源对象属性值为null时,是否将值复制给目标对象</param> public static void copy<s, t>(s source, t target, bool copynull = true) { string name = string.format("{0}_{1}_{2}", typeof(s), typeof(t), copynull); object targetcopier; if (!copiers.trygetvalue(name, out targetcopier)) { action<s, t> copier = createcopier<s, t>(copynull); copiers.tryadd(name, copier); targetcopier = copier; 我得到什么 } action<s, t> action = (action<s, t>)targetcopier; action(source, target); } /// <summary> /// 为指定的两种类型编译生成属性复制委托 /// </summary> /// <typeparam name="s"></typeparam> /// <typeparam name="t"></typeparam> /// <param name="copynull">源对象属性值为null时,是否将值复制给目标对象</param> /// <returns></returns> private static action<s, t> createcopier<s, t>(bool copynull) { parameterexpression source = parameter(typeof(s)); parameterexpression target = parameter(typeof(t)); var sourceprops = typeof(s).getproperties(bindingflags.instance | bindingflags.public).where(p => p.canread).tolist(); var targetprops = typeof(t).getproperties(bindingflags.instance | bindingflags.public).where(p => p.canwrite).tolist(); // 查找可进行赋值的属性 var copyprops = targetprops.where(tprop => sourceprops.where(sprop => sprop.name == tprop.name// 名称一致 且 && ( sprop.propertytype == tprop.propertytype// 属性类型一致 或 || sprop.propertytype.isassignablefrom(tprop.propertytype) // 源属性类型 为 目标属性类型 的 子类;eg:object target = string source; 或 || (tprop.propertytype.isvaluetype && sprop.propertytype.isvaluetype && // 属性为值类型且基础类型一致,但目标属性为可空类型 eg:int? num = int num; ((tprop.propertytype.generictypearguments.length > 0 ? tprop.propertytype.generictypearguments[0] : tprop.propertytype) == sprop.propertytype)) )).count() > 0); list<expression> expressionlist = new list<expression>(); foreach (var prop in copyprops) { if (prop.propertytype.isvaluetype)// 属性为值类型 { propertyinfo sprop = typeof(s).getproperty(prop.name); propertyinfo tprop = typeof(t).getproperty(prop.name); if (sprop.propertytype == tprop.propertytype)// 属性类型一致 eg:int num = int num; 或 int? num = int? num; { var assign = assign(property(target, prop.name), property(source, prop.name)); expressionlist.add(assign); } el if (sprop.propertytype.generictypearguments.length <= 0 && tprop.propertytype.generictypearguments.length > 0)// 属性类型不一致且目标属性类型为可空类型 eg:int? num = int num; { var convert = convert(expression.property(source, prop.name), tprop.propertytype); var cvassign = assign(expression.property(target, prop.name), convert); expressionlist.add(cvassign); } } el// 属性为引用类型 { var assign = assign(property(target, prop.name), property(source, prop.name));// 编译生成属性赋值语句 target.{propeum是什么单位rtyname} = source.{propertyname}; var sourcepropisnull = equal(constant(null, prop.propertytype), property(source, prop.name));// 判断源属性值是否为null;编译生成 source.{propertyname} == null var tnull = istrue(constant(copynull));// 判断是否复制null值 编译生成 copynull == true var tnulltest = ifthen(tnull, assign); var condition = ifthenel(sourcepropisnull, tnulltest, assign); /** * 编译生成 * if(source.{propertyname} == null) * { * if(tnull) * { * target.{propertyname} = source.{propertyname}; * } * } * el * { * target.{propertyname} = source.{propertyname}; * } */ expressionlist.add(condition); } } var block = block(expressionlist.toarray()); expression<action<s, t>> lambda = lambda<action<s, t>>(block, source, target); return lambda.compile(); } }}
如果完整复制,去掉逻辑判断,同时可通过泛型类,不在使用字典,性能还可以提升。
using system;using system.linq;using system.linq.expressions;using system.reflection;namespace common{ public static class fastcopy<s, t> { static action<s, t> action = createcopier(); /// <summary> /// 复制两个对象同名属性值 /// </summary> /// <typeparam name="s"></typeparam> /// <typeparam name="t"></typeparam> /// <param name="source">源对象</param> /// <param name="target">目标对象</param> 创新活动/// <param name="copynull">源对象属性值为null时,是否将值复制给目标对象</param> public static void copy(s source, t target, bool copynull = true) { action(source, target); } /// <summary> /// 为指定的两种类型编译生成属性复制委托 /// </summary> /// <typeparam name="s"></typeparam> /// <typepar2016msiam name="t"></typeparam> /// <param name="copynull">源对象属性值为null时,是否将值复制给目标对象</param> /// <returns></returns> private static action<s, t> createcopier() { parameterexpression source = expression.parameter(typeof(s)); parameterexpression target = expression.parameter(typeof(t)); var sourceprops = typeof(s).getproperties(bindingflags.instance | bindingflags.public).where(p => p.canread).tolist(); var targetprops = typeof(t).getproperties(bindingflags.instance | bindingflags.public).where(p => p.canwrite).tolist(); // 查找可进行赋值的属性 var copyprops = targetprops.where(tprop => sourceprops.where(sprop => sprop.name == tprop.name// 名称一致 且 && ( sprop.propertytype == tprop.propertytype// 属性类型一致 )).count() > 0); var block = expression.block(from p in copyprops lect expression.assign(expression.property(target, p.name), expression.property(source, p.name))); expression<action<s, t>> lambda = expression.lambda<action<s, t>>(block, source, target); return lambda.compile(); } }}
百万次耗时:100ms左右
到此这篇关于c#使用表达式树实现对象复制的示例代码的文章就介绍到这了,更多相关c#表达式树对象复制内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!
本文发布于:2023-04-04 10:00:35,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/546ec7c2cca659748c6b53bdfd22ef03.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:C#使用表达式树实现对象复制的示例代码.doc
本文 PDF 下载地址:C#使用表达式树实现对象复制的示例代码.pdf
留言与评论(共有 0 条评论) |