public static T DeepClone<T>(T obj)
{
T objResult;
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ms, obj);
ms.Position = 0;
objResult = (T)bf.Deserialize(ms);
}
return objResult;
}
List<T> myList = ...;
List<T> cloneOfMyList = new List<T>(myList);
对 myList 的更改(例如插入或移除)不会影响 cloneOfMyList ,反之亦然 .
但是,两个列表包含的实际对象仍然相同 .
430
要克隆列表,只需调用.ToList()
Microsoft (R) Roslyn C# Compiler version 2.3.2.62116
Loading context from 'CSharpInteractive.rsp'.
Type "#help" for more information.
> var x = new List<int>() { 3, 4 };
> var y = x.ToList();
> x.Add(5)
> x
List<int>(3) { 3, 4, 5 }
> y
List<int>(2) { 3, 4 }
>
public static Object CloneType(Object objtype)
{
Object lstfinal = new Object();
using (MemoryStream memStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
binaryFormatter.Serialize(memStream, objtype); memStream.Seek(0, SeekOrigin.Begin);
lstfinal = binaryFormatter.Deserialize(memStream);
}
return lstfinal;
}
67
public class CloneableList<T> : List<T>, ICloneable where T : ICloneable
{
public object Clone()
{
var clone = new List<T>();
ForEach(item => clone.Add((T)item.Clone()));
return clone;
}
}
75
public List<TEntity> Clone<TEntity>(List<TEntity> o1List) where TEntity : class , new()
{
List<TEntity> retList = new List<TEntity>();
try
{
Type sourceType = typeof(TEntity);
foreach(var o1 in o1List)
{
TEntity o2 = new TEntity();
foreach (PropertyInfo propInfo in (sourceType.GetProperties()))
{
var val = propInfo.GetValue(o1, null);
propInfo.SetValue(o2, val);
}
retList.Add(o2);
}
return retList;
}
catch
{
return retList;
}
}
namespace extension
{
public class ext
{
public static List<double> clone(this List<double> t)
{
List<double> kop = new List<double>();
int x;
for (x = 0; x < t.Count; x++)
{
kop.Add(t[x]);
}
return kop;
}
};
}
您可以使用其值类型成员克隆所有对象,例如,考虑以下类:
public class matrix
{
public List<List<double>> mat;
public int rows,cols;
public matrix clone()
{
// create new object
matrix copy = new matrix();
// firstly I can directly copy rows and cols because they are value types
copy.rows = this.rows;
copy.cols = this.cols;
// but now I can no t directly copy mat because it is not value type so
int x;
// I assume I have clone method for List<double>
for(x=0;x<this.mat.count;x++)
{
copy.mat.Add(this.mat[x].clone());
}
// then mat is cloned
return copy; // and copy of original is returned
}
};
注意:如果对复制(或克隆)进行任何更改,则不会影响原始对象 .
2
如果您需要具有相同容量的克隆列表,可以尝试以下操作:
public static List<T> Clone<T>(this List<T> oldList)
{
var newList = new List<T>(oldList.Capacity);
newList.AddRange(oldList);
return newList;
}
public static T DeepCopy<T>(this T value)
{
JavaScriptSerializer js = new JavaScriptSerializer();
string json = js.Serialize(value);
return js.Deserialize<T>(json);
}
[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Person
{
...
Job JobDescription
...
}
[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Job
{...
}
private static readonly Type stringType = typeof (string);
public static class CopyFactory
{
static readonly Dictionary<Type, PropertyInfo[]> ProperyList = new Dictionary<Type, PropertyInfo[]>();
private static readonly MethodInfo CreateCopyReflectionMethod;
static CopyFactory()
{
CreateCopyReflectionMethod = typeof(CopyFactory).GetMethod("CreateCopyReflection", BindingFlags.Static | BindingFlags.Public);
}
public static T CreateCopyReflection<T>(T source) where T : new()
{
var copyInstance = new T();
var sourceType = typeof(T);
PropertyInfo[] propList;
if (ProperyList.ContainsKey(sourceType))
propList = ProperyList[sourceType];
else
{
propList = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
ProperyList.Add(sourceType, propList);
}
foreach (var prop in propList)
{
var value = prop.GetValue(source, null);
prop.SetValue(copyInstance,
value != null && prop.PropertyType.IsClass && prop.PropertyType != stringType ? CreateCopyReflectionMethod.MakeGenericMethod(prop.PropertyType).Invoke(null, new object[] { value }) : value, null);
}
return copyInstance;
}
我通过使用Watcher类以一种简单的方式测量它 .
var person = new Person
{
...
};
for (var i = 0; i < 1000000; i++)
{
personList.Add(person);
}
var watcher = new Stopwatch();
watcher.Start();
var copylist = personList.Select(CopyFactory.CreateCopyReflection).ToList();
watcher.Stop();
var elapsed = watcher.Elapsed;
23 回答
您可以使用扩展方法 .
如果您的元素是值类型,那么您可以这样做:
但是,如果它们是引用类型并且您需要深层复制(假设您的元素正确实现
ICloneable
),您可以执行以下操作:显然,在上面的泛型中替换
ICloneable
并使用实现ICloneable
的元素类型进行强制转换 .如果您的元素类型不支持
ICloneable
但确实有复制构造函数,那么您可以这样做:就个人而言,我会避免
ICloneable
,因为需要保证所有成员的深层副本 . 相反,我建议复制构造函数或像YourType.CopyFrom(YourType itemToCopy)
这样的工厂方法返回YourType
的新实例 .这些选项中的任何一个都可以通过方法(扩展名或其他方式)进行包装 .
这是使用C#和.NET 2.0实现此目的的一种方法 . 您的对象需要
[Serializable()]
. 目标是丢失所有引用并构建新引用 .对于浅表副本,您可以改为使用泛型List类的GetRange方法 .
引用自:Generics Recipes
稍作修改后你也可以克隆:
除非您需要实际克隆
List<T>
中的每个对象,否则克隆列表的最佳方法是创建一个新列表,其中旧列表作为集合参数 .对
myList
的更改(例如插入或移除)不会影响cloneOfMyList
,反之亦然 .但是,两个列表包含的实际对象仍然相同 .
要克隆列表,只需调用.ToList()
使用AutoMapper(或您喜欢的任何映射库)来克隆是简单且可维护的 .
定义您的映射:
做魔术:
如果你只关心 Value 类型......
你知道的类型:
如果您之前不知道类型,则需要辅助函数:
正义:
如果您已在项目中引用了Newtonsoft.Json,并且您的对象可序列化,则可以始终使用:
可能不是最有效的方法,但除非你做了1000次,否则你可能甚至没有注意到速度差异 .
您也可以使用
ToArray
将列表转换为数组,然后使用Array.Clone(...)
克隆数组 . 根据您的需要,Array类中包含的方法可以满足您的需求 .您可以使用扩展方法:
您可以使用其值类型成员克隆所有对象,例如,考虑以下类:
注意:如果对复制(或克隆)进行任何更改,则不会影响原始对象 .
如果您需要具有相同容量的克隆列表,可以尝试以下操作:
我的朋友Gregor Martinovic和我使用JavaScript Serializer提出了这个简单的解决方案 . 没有必要将类标记为Serializable,并且在我们的测试中使用Newtonsoft JsonSerializer比使用BinaryFormatter更快 . 扩展方法可用于每个对象 .
标准.NET JavascriptSerializer选项:
使用Newtonsoft JSON加快选项:
我为自己做了一些扩展,它转换ICollection没有实现IClonable的项目
我使用automapper来复制一个对象 . 我只是设置了一个映射,将一个对象映射到自身 . 您可以以任何方式包装此操作 .
http://automapper.codeplex.com/
以下代码应转移到列表中,只需进行少量更改 .
基本上它通过在每个连续循环中从更大范围插入新的随机数来工作 . 如果已存在与其相同或更高的数字,则将这些随机数向上移一,以便将它们转移到新的更大范围的随机索引中 .
另一件事:你可以使用反射 . 如果你正确地缓存它,那么它将在5.6秒内克隆1,000,000个对象(遗憾的是,内部对象为16.4秒) .
我通过使用Watcher类以一种简单的方式测量它 .
RESULT: 使用内部对象PersonInstance - 16.4,PersonInstance = null - 5.6
CopyFactory只是我的测试类,我有十几个测试,包括表达式的使用 . 您可以在扩展程序中以其他形式实现此功能 . 不要忘记缓存 .
我还没有测试序列化,但我对百万级课程的改进表示怀疑 . 我会尝试一些快速的protobuf / newton .
P.S . :为了简单起见,我在这里只使用了自动 property . 我可以使用FieldInfo进行更新,或者您应该通过自己的方式轻松实现 .
我最近测试了Protocol Buffers具有DeepClone功能的串行器开箱即用 . 它在一百万个简单对象上以4.2秒获胜,但是当涉及内部对象时,它以7.4秒的结果获胜 .
SUMMARY: 如果您无法访问这些课程,那么这将有所帮助 . 否则它取决于对象的数量 . 我认为你可以使用多达10,000个对象的反射(可能少一点),但是对于更多,协议缓冲序列化器将表现更好 .
有一种使用JSON序列化器和反序列化器在C#中克隆对象的简单方法 .
您可以创建扩展类:
克隆和对象: