先上結論 | Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated | | | :| :| :| :| :| :| | JSONConvert | 2,273.02 ns | 43.758 ns | 52.091 ns | 0.6599 | ...
先上結論
Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
---|---|---|---|---|---|---|
JSONConvert | 2,273.02 ns | 43.758 ns | 52.091 ns | 0.6599 | - | 4160 B |
Reflection | 1,009.13 ns | 10.110 ns | 8.442 ns | 0.0629 | - | 400 B |
BinaryFormatter | 8,146.04 ns | 85.914 ns | 67.076 ns | 1.6022 | 0.0153 | 10088 B |
Expression | 14.70 ns | 0.315 ns | 0.430 ns | 0.0063 | - | 40 B |
由測試得出結論:
1 首選Expression表達式樹,性能大幅領先於反射,耗時僅為反射的1/70
2 反射,最常用的深度拷貝方法,書寫比較簡單
3 JSONConvert,最簡答的寫法,適用於偶爾需要深度拷貝的時候使用
4 BinaryFormatter,不推薦,需要在類上加上序列化聲明,並且在.NET 5.0中該方法已經被微軟聲明為過期.
代碼
public static class DeepCopyUtil
{
/// <summary>
/// Json深度拷貝
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static T DeepCopyJson<T>(T obj)
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
}
/// <summary>
/// 反射深度拷貝
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static T DeepCopyReflection<T>(T obj)
{
var type = obj.GetType();
object o = Activator.CreateInstance(type);
System.Reflection.PropertyInfo[] PI = type.GetProperties();
for (int i = 0; i < PI.Count(); i++)
{
System.Reflection.PropertyInfo P = PI[i];
P.SetValue(o, P.GetValue(obj));
}
return (T)o;
}
public static T DeepCopyMemory<T>(T obj)
{
object retval;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
//序列化成流
bf.Serialize(ms, obj);
ms.Seek(0, SeekOrigin.Begin);
//反序列化成對象
retval = bf.Deserialize(ms);
ms.Close();
}
return (T)retval;
}
public static class TransExp<TIn, TOut>
{
private static readonly Func<TIn, TOut> cache = GetFunc();
private static Func<TIn, TOut> GetFunc()
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
List<MemberBinding> memberBindingList = new List<MemberBinding>();
foreach (var item in typeof(TOut).GetProperties())
{
if (!item.CanWrite) continue;
MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
MemberBinding memberBinding = Expression.Bind(item, property);
memberBindingList.Add(memberBinding);
}
MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] { parameterExpression });
return lambda.Compile();
}
public static TOut Trans(TIn tIn)
{
return cache(tIn);
}
}
}