博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.NetCore 利用反射处理RESTful的更新自动赋值
阅读量:6590 次
发布时间:2019-06-24

本文共 4781 字,大约阅读时间需要 15 分钟。

背景

在RESTful Api模式开发Api,Patch更新时,频繁的遇到不同类型但属性相同的Dto到Model字段赋值的情况,

网上通用的类库是AutoMapper,但遇到了问题,查了Git也提出了问题,并未能解决。

问题

Post、Get等覆盖式传值时都能满足需求,唯独当Dto字段的值类型设为Nullable(如int?、bool?)时会被覆盖为默认值。

相关技术

1、Lambda表达式

2、反射

解决方案

利用反射查找类的字段名称与字段类型,并将具备相同属性名的源Class属性值赋值到目标Class,

如遇到源Class属为Null(引用空 或 Nullable泛型类型Null)跳过该属赋值。

using System;using System.Collections.Concurrent;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Linq.Expressions;using System.Reflection;namespace Zhiqing.Helpers.Lambdas{    ///     /// 快速复制,并忽略NULL值    ///     public static class FastCopy    {        static Action
CreateCopier
() { // 源 var source = Expression.Parameter(typeof(S)); // 目标 var target = Expression.Parameter(typeof(T)); // 源 所有属性 var props1 = typeof(S).GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.CanRead).ToList(); // 目标 所有属性 var props2 = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.CanWrite).ToList(); // 共有属性 var props = props1.Where(x => props2.Any(y => y.Name == x.Name)); IEnumerable
assets = new List
(); foreach (var item in props) { // 目标 var tItem = Expression.Property(target, item.Name); var tType = tItem.Type; var tIsNullable = tType.IsGenericType && tType.GetGenericTypeDefinition() == typeof(Nullable<>); // 源 var sItem = Expression.Property(source, item.Name); var sType = sItem.Type; var sIsNullable = sType.IsGenericType && sType.GetGenericTypeDefinition() == typeof(Nullable<>); Debug.WriteLine(sIsNullable); // =================================== // 注释:Nullable实际是个泛型,赋值是需要转为实际类型才可赋值,否咋泛型给实际类型赋值引发异常 // 案例:int? s = 1;int t = s; 会引发异常 // 解决:int? s = 1;int t = Convert.ToInt32(s); 转换后解决 // 另外:Lamnda表达式应使用 Expression.Convert(); 转换 // 源是可为空类型 if (sIsNullable) { // 目标可为空 if (tIsNullable) { // 赋值表达式 var asset = Expression.Assign(tItem, sItem); // 当源不为空的时候赋值 var notNull = Expression.IfThen(Expression.NotEqual(sItem, Expression.Constant(null)), asset); // 加入表达式树 assets = assets.Append(notNull); } // 目标不可为空 else { // 转换源为实际类型 var sItemConverted = Expression.Convert(sItem, sType.GetGenericArguments().First()); // 赋值表达式 var asset = Expression.Assign(tItem, sItemConverted); // 当源不为空的时候赋值 var notNull = Expression.IfThen(Expression.NotEqual(sItem, Expression.Constant(null)), asset); // 加入表达式树 assets = assets.Append(notNull); } } // 源不是可为空类型 else { // 源是否值类型 var sIsValueType = sType.IsValueType; if (sIsValueType) { // 赋值表达式 var asset = Expression.Assign(tItem, sItem); // 加入表达式树 assets = assets.Append(asset); } // 不是值类型 else { // 赋值表达式 var asset = Expression.Assign(tItem, sItem); // 当源不为空的时候赋值 var notNull = Expression.IfThen(Expression.NotEqual(sItem, Expression.Constant(null)), asset); // 加入表达式树 assets = assets.Append(notNull); } } } // 赋值 var tempBlock = Expression.Block(assets); return Expression.Lambda
>(tempBlock, source, target).Compile(); } static ConcurrentDictionary
actions = new ConcurrentDictionary
(); ///
/// 快速的拷贝同名公共属性。忽略差异的字段。 /// ///
///
///
///
public static void Copy
(S from, T to) { string name = string.Format("{0}_{1}", typeof(S), typeof(T)); if (!actions.TryGetValue(name, out object obj)) { var ff = CreateCopier
(); actions.TryAdd(name, ff); obj = ff; } var act = (Action
)obj; act(from, to); } }}

使用案例

FastCopy.Copy
(updateDto, modelCard);

转载地址:http://gekio.baihongyu.com/

你可能感兴趣的文章
关于MapReduce单词统计的例子:
查看>>
【php】利用php的构造函数与析构函数编写Mysql数据库查询类 (转)
查看>>
导出DLLRegisterServer接口遇到的问题
查看>>
压缩算法
查看>>
ios和android的发展前景比较
查看>>
[转载]SpringMVC的Model参数绑定方式
查看>>
Linux socket多进程服务器框架三
查看>>
Debug.print的用法
查看>>
常用名词
查看>>
计算机硬件常识
查看>>
第一百三十四节,JavaScript,封装库--遮罩锁屏
查看>>
【转】cookie如何共享到各个浏览器
查看>>
自制基于HMM的python中文分词器
查看>>
如何在Root的手机上开启ViewServer,使得HierachyViewer能够连接
查看>>
重写和重载
查看>>
RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2-新增锁定用户与解除锁定用户的功能...
查看>>
vue1.0 的过滤器
查看>>
如何删除anaconda
查看>>
Mybatis3.3——源码阅读笔记
查看>>
oracle中的trunc函数操作
查看>>