我目前有2种不同的解决方案为此,一种使用反射,另一种不使用反射:
1.) With a 通用扩展方法 (plus 反射 http://msdn.microsoft.com/en-us/library/ms173183(v=vs.100).aspx)你可以在 C# 中这样做:
public static class Extension
{
public static T CreateCopy<T>(this T src)
where T: new()
{
if (src == null) return default(T); // just return null
T tgt = new T(); // create new instance
// then copy all properties
foreach (var pS in src.GetType().GetProperties())
{
foreach (var pT in tgt.GetType().GetProperties())
{
if (pT.Name != pS.Name) continue;
(pT.GetSetMethod()).Invoke(tgt, new object[] {
pS.GetGetMethod().Invoke(src, null) });
}
};
return tgt;
} // method
} // class
这非常强大,因为现在您可以克隆每个对象,不仅仅是来自您编写的类的对象,而是来自所有类的对象包括系统类.NET 框架的。并且由于反思,你不需要知道它的属性,它们会被自动复制。
Example
使用方法CreateCopy()
,假设你有一个Customer
类和一个Order
类,并且您需要使用新 ID 创建副本(不是引用)。然后您可以执行以下操作:
Order CopyOrderWithNewPK(Order item)
{
Order newItem = item.CreateCopy(); // use ext. method to copy properties
newItem.OrderId = new Guid(); // create new primary key for the item
return newItem;
}
毫不奇怪,对于 Customer 类来说,它看起来是一样的:
Customer CopyCustomerWithNewPK(Customer item)
{
Customer newItem = item.CreateCopy(); // use ext. method to copy properties
newItem.CustomerId = new Guid(); // create new primary key for the item
return newItem;
}
Note示例类中定义的所有属性的值都会自动复制。如果您不拥有源代码,您甚至可以克隆第 3 方程序集的对象。代价是反射方法速度较慢。
2.)还有另一种方法可以做到这一点没有反射,灵感来自于this https://stackoverflow.com/q/11599526/1016343问题。一个优点是它甚至能够克隆实体框架的对象(例如将实体对象附加和重新附加到不同的数据上下文):
// using System.Runtime.Serialization;
public class Cloner<T>
{
readonly DataContractSerializer _serializer
= new DataContractSerializer(typeof(T));
/// <summary>
/// Clone an object graph
/// </summary>
/// <param name="graph"></param>
/// <returns></returns>
public T Clone(T graph)
{
MemoryStream stream = new MemoryStream();
_serializer.WriteObject(stream, graph);
stream.Seek(0, SeekOrigin.Begin);
return (T)_serializer.ReadObject(stream);
}
}
为了不破坏上面的例子,你可以改变扩展方法CreateCopy
如下:
public static class Extension
{
public static T CreateCopy<T>(this T src)
where T: new()
{
return (new Cloner<T>()).Clone(src);
}
}
Note:虽然Cloner
正在使用System.Runtime.Serialization
,被克隆的对象确实not需要可序列化。这可能是一个优势,我见过的其他解决方案只能克隆可序列化对象。