92 lines
4.2 KiB
C#
92 lines
4.2 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Reflection;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
|
|||
|
|
namespace SamplePre.Common.Helper
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 实体对象复制工具类(反射实现)
|
|||
|
|
/// 适配.NET Framework 4.8,支持同实体/不同实体间同名字段值复制(浅拷贝)
|
|||
|
|
/// </summary>
|
|||
|
|
public static class ObjectCopyHelper
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 核心方法:将源对象的同名字段值复制到目标对象
|
|||
|
|
/// </summary>
|
|||
|
|
/// <typeparam name="TSource">源对象类型</typeparam>
|
|||
|
|
/// <typeparam name="TTarget">目标对象类型</typeparam>
|
|||
|
|
/// <param name="source">源对象(提供值)</param>
|
|||
|
|
/// <param name="target">目标对象(接收值,需提前实例化)</param>
|
|||
|
|
/// <param name="ignoreCase">是否忽略属性名大小写(默认true:Name和name视为同一个)</param>
|
|||
|
|
/// <param name="ignoreNull">是否忽略源对象的null值(默认false:源null会覆盖目标值)</param>
|
|||
|
|
public static void CopyProperties<TSource, TTarget>(this TSource source, TTarget target,
|
|||
|
|
bool ignoreCase = true, bool ignoreNull = false)
|
|||
|
|
where TSource : class // 源对象不能为空引用类型
|
|||
|
|
where TTarget : class // 目标对象不能为空引用类型
|
|||
|
|
{
|
|||
|
|
// 空值校验
|
|||
|
|
if (source == null) throw new ArgumentNullException(nameof(source), "源对象不能为null");
|
|||
|
|
if (target == null) throw new ArgumentNullException(nameof(target), "目标对象不能为null");
|
|||
|
|
|
|||
|
|
// 获取源对象和目标对象的属性信息(仅获取公共可读写属性)
|
|||
|
|
PropertyInfo[] sourceProps = typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
|||
|
|
PropertyInfo[] targetProps = typeof(TTarget).GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
|||
|
|
|
|||
|
|
// 遍历源对象的所有属性,匹配目标对象的同名字段
|
|||
|
|
foreach (PropertyInfo sourceProp in sourceProps)
|
|||
|
|
{
|
|||
|
|
// 跳过源对象中不可读的属性(无getter)
|
|||
|
|
if (!sourceProp.CanRead) continue;
|
|||
|
|
|
|||
|
|
// 获取源对象当前属性的值
|
|||
|
|
object sourceValue = sourceProp.GetValue(source, null);
|
|||
|
|
|
|||
|
|
// 忽略源对象的null值(若开启该配置)
|
|||
|
|
if (ignoreNull && sourceValue == null) continue;
|
|||
|
|
|
|||
|
|
// 在目标对象中查找同名字段(支持忽略大小写)
|
|||
|
|
PropertyInfo targetProp = Array.Find(targetProps, p =>
|
|||
|
|
string.Equals(p.Name, sourceProp.Name, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal));
|
|||
|
|
|
|||
|
|
// 目标对象无该属性/目标属性不可写/类型不匹配 → 跳过
|
|||
|
|
if (targetProp == null || !targetProp.CanWrite
|
|||
|
|
|| !sourceProp.PropertyType.IsAssignableFrom(targetProp.PropertyType))
|
|||
|
|
{
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 给目标对象的属性赋值
|
|||
|
|
targetProp.SetValue(target, sourceValue, null);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 重载方法:快速复制(默认忽略大小写、不忽略null)
|
|||
|
|
/// </summary>
|
|||
|
|
public static void CopyProperties<TSource, TTarget>(this TSource source, TTarget target)
|
|||
|
|
where TSource : class
|
|||
|
|
where TTarget : class
|
|||
|
|
{
|
|||
|
|
CopyProperties(source, target, true, false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 便捷方法:创建目标对象并完成复制(一步到位,无需提前实例化目标对象)
|
|||
|
|
/// </summary>
|
|||
|
|
public static TTarget CopyToNew<TSource, TTarget>(this TSource source,
|
|||
|
|
bool ignoreCase = true, bool ignoreNull = false)
|
|||
|
|
where TSource : class
|
|||
|
|
where TTarget : class, new() // 目标对象必须有无参构造函数
|
|||
|
|
{
|
|||
|
|
if (source == null) throw new ArgumentNullException(nameof(source));
|
|||
|
|
// 实例化目标对象并赋值
|
|||
|
|
TTarget target = new TTarget();
|
|||
|
|
source.CopyProperties(target, ignoreCase, ignoreNull);
|
|||
|
|
return target;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|