[英]Deep Copy of a C# Object
我正在处理一些用 C# 编写的代码。 在这个应用程序中,我有一个自定义集合,定义如下:
public class ResultList<T> : IEnumerable<T>
{
public List<T> Results { get; set; }
public decimal CenterLatitude { get; set; }
public decimal CenterLongitude { get; set; }
}
结果使用的类型是三种自定义类型之一。 每个自定义类型的属性只是原始类型(整数、字符串、布尔值、整数?、布尔值?)。 以下是其中一种自定义类型的示例:
public class ResultItem
{
public int ID { get; set; }
public string Name { get; set; }
public bool? isLegit { get; set; }
}
如何执行我创建的 ResultList 对象的深层复制。 我找到了这篇文章: Generic method to create deep copy of all elements in a collection 。 但是,我不知道该怎么做。
涉及最少编码工作的方法是通过BinaryFormatter
进行序列化和反序列化。
您可以定义以下扩展方法(取自Kilhoffer 的回答):
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
...然后只需调用:
ResultList<T> clone = DeepClone(original);
您的 ResultList 类不能与 Jon Skeet 的示例一起使用的原因之一是它没有实现 ICloneable 接口。
在您需要克隆的所有类上实现 ICloneable,例如
public class ResultItem : ICloneable
{
public object Clone()
{
var item = new ResultItem
{
ID = ID,
Name = Name,
isLegit = isLegit
};
return item;
}
}
还有在 ResultList 上:
public class ResultList<T> : IEnumerable<T>, ICloneable where T : ICloneable
{
public List<T> Results { get; set; }
public decimal CenterLatitude { get; set; }
public decimal CenterLongitude { get; set; }
public object Clone()
{
var list = new ResultList<T>
{
CenterLatitude = CenterLatitude,
CenterLongitude = CenterLongitude,
Results = Results.Select(x => x.Clone()).Cast<T>().ToList()
};
return list;
}
}
然后制作对象的深层副本:
resultList.clone();
扩展@Georgi-it,我不得不修改他的代码来处理类型继承List的属性:
public static class ObjectCloner {
public static T Clone<T>(object obj, bool deep = false) where T : new() {
if (!(obj is T)) {
throw new Exception("Cloning object must match output type");
}
return (T)Clone(obj, deep);
}
public static object Clone(object obj, bool deep) {
if (obj == null) {
return null;
}
Type objType = obj.GetType();
if (objType.IsPrimitive || objType == typeof(string) || objType.GetConstructors().FirstOrDefault(x => x.GetParameters().Length == 0) == null) {
return obj;
}
List<PropertyInfo> properties = objType.GetProperties().ToList();
if (deep) {
properties.AddRange(objType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic));
}
object newObj = Activator.CreateInstance(objType);
foreach (var prop in properties) {
if (prop.GetSetMethod() != null) {
var proceed = true;
if (obj is IList) {
var listType = obj.GetType().GetProperty("Item").PropertyType;
if (prop.PropertyType == listType) {
proceed = false;
foreach (var item in obj as IList) {
object clone = Clone(item, deep);
(newObj as IList).Add(clone);
}
}
}
if (proceed) {
object propValue = prop.GetValue(obj, null);
object clone = Clone(propValue, deep);
prop.SetValue(newObj, clone, null);
}
}
}
return newObj;
}
}
这是我需要和写的东西,它使用反射来复制每个属性(如果指定的话,还有私有的)
public static class ObjectCloner
{
public static T Clone<T>(object obj, bool deep = false) where T : new()
{
if (!(obj is T))
{
throw new Exception("Cloning object must match output type");
}
return (T)Clone(obj, deep);
}
public static object Clone(object obj, bool deep)
{
if (obj == null)
{
return null;
}
Type objType = obj.GetType();
if (objType.IsPrimitive || objType == typeof(string) || objType.GetConstructors().FirstOrDefault(x => x.GetParameters().Length == 0) == null)
{
return obj;
}
List<PropertyInfo> properties = objType.GetProperties().ToList();
if (deep)
{
properties.AddRange(objType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic));
}
object newObj = Activator.CreateInstance(objType);
foreach (var prop in properties)
{
if (prop.GetSetMethod() != null)
{
object propValue = prop.GetValue(obj, null);
object clone = Clone(propValue, deep);
prop.SetValue(newObj, clone, null);
}
}
return newObj;
}
}
对于对象的深度应对,您可以使用以下代码:
public static T DeepCopy<T>(T obj) {
var str = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
var ret = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(str);
return ret;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.