using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace SamplePre.Common.Helper
{
///
/// 实体对象复制工具类(反射实现)
/// 适配.NET Framework 4.8,支持同实体/不同实体间同名字段值复制(浅拷贝)
///
public static class ObjectCopyHelper
{
///
/// 核心方法:将源对象的同名字段值复制到目标对象
///
/// 源对象类型
/// 目标对象类型
/// 源对象(提供值)
/// 目标对象(接收值,需提前实例化)
/// 是否忽略属性名大小写(默认true:Name和name视为同一个)
/// 是否忽略源对象的null值(默认false:源null会覆盖目标值)
public static void CopyProperties(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);
}
}
///
/// 重载方法:快速复制(默认忽略大小写、不忽略null)
///
public static void CopyProperties(this TSource source, TTarget target)
where TSource : class
where TTarget : class
{
CopyProperties(source, target, true, false);
}
///
/// 便捷方法:创建目标对象并完成复制(一步到位,无需提前实例化目标对象)
///
public static TTarget CopyToNew(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;
}
}
}