有没有办法在C#中复制一个对象?类似这样的操作:
我希望它们是相等的,这样所有的数据成员都是相同的,但不共享同一内存位置。
var dupe = MyClass(original);
我希望它们是相等的,这样所有的数据成员都是相同的,但不共享同一内存位置。
var dupe = MyClass(original);
public static T DeepCopy<T>(T other)
{
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, other);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
Object.MemberwiseClone()
方法,但这是一个受保护的方法,意味着你只能在类内部使用它。BinaryFormatter
可能包含远程代码执行的危险性的警告...你可以使用提供链接中列出的首选替代方法。[Serializable]
。否则你就得使用其他实现方式。 - vgru并非所有类都具有此功能。如果一个类具有这个功能,那么它可能会提供一个Clone
方法。为了帮助实现自己的类的该方法,System.Object
中定义了一个MemberwiseClone
受保护方法,它可以对当前实例进行浅复制(即,字段被复制;如果它们是引用类型,则引用将指向原始位置)。
SubCentreMessage actual;
actual = target.FindSubCentreFullDetails(120); //for Albany
SubCentreMessage s = new SubCentreMessage();
//initialising s with the same values as
foreach (var property in actual.GetType().GetProperties())
{
PropertyInfo propertyS = s.GetType().GetProperty(property.Name);
var value = property.GetValue(actual, null);
propertyS.SetValue(s, property.GetValue(actual, null), null);
}
public class MyClass()
{
public MyClass() {}
protected MyClass(MyClass other)
{
// Cloning code goes here...
}
public MyClass Clone()
{
return new MyClass(this);
}
}
我认为作者在询问拷贝构造函数的问题...
答案是“可以,但只有在自己实现时”,没有一种“自动”的方式可以做到这一点,除非使用一些重型修补(即:反射):
class MyClass {
private string _name;
// standard constructor, so that we can make MyClass's without troubles
public MyClass(string name) {_name = name}
public MyClass(MyClass old) {
_name = old._name;
// etc...
}
}
在这方面需要注意的另一件事是 IClonable
接口,以及它提供的 .Clone()
方法。同时,Object
类提供的 .MemberwiseClone()
受保护方法也可以帮助实现这两个方法。
使用JSON怎么样?
您可以从以下网址获取JSON软件包:https://www.nuget.org/packages/Newtonsoft.Json/
using Newtonsoft.Json;
public static List<T> CopyAll<T>(this List<T> list) {
List<T> ret = new List<T>();
string tmpStr = JsonConvert.SerializeObject(list);
ret = JsonConvert.DeserializeObject<List<T>>(tmpStr);
return ret;
}
这里有一些合理的解决方案,序列化是一种有效的方式,每个类也可以使用克隆方法。我写了一些代码并且在测试中似乎可行。
using System.Reflection; using System.Text.StringBuilder();
public static T CopyClass2<T>(T obj){
T objcpy = (T)Activator.CreateInstance(typeof(T));
obj.GetType().GetProperties().ToList()
.ForEach( p => objcpy.GetType().GetProperty(p.Name).SetValue(objcpy, p.GetValue(obj)));
return objcpy;
以下是更加详细的版本,上面的内容可能假设你理解Lambda表达式,这并不常见。如果你更注重可读性(完全有效),我建议使用下面的内容。
public static T CopyClass<T>(T obj)
{
T objcpy = (T)Activator.CreateInstance(typeof(T));
foreach (var prop in obj.GetType().GetProperties())
{
var value = prop.GetValue(obj);
objcpy.GetType().GetProperty(prop.Name).SetValue(objcpy, value);
}
return objcpy;
使用此方法列出属性,以查看它是否被复制到新引用中。简单来说,它不会列出非基元(结构化类型)的属性,因此您将获得一个类名。
public static string ListAllProperties<T>(T obj)
{
StringBuilder sb = new System.Text.StringBuilder();
PropertyInfo[] propInfo = obj.GetType().GetProperties();
foreach (var prop in propInfo)
{
var value = prop.GetValue(obj) ?? "(null)";
sb.AppendLine(prop.Name + ": " + value.ToString());
}
return sb.ToString();
}
public object Clone()
{
object clonedObject = null;
BinaryFormatter formatter = new BinaryFormatter();
using (Stream stream = new MemoryStream())
{
formatter.Serialize(stream, this);
stream.Seek(0, SeekOrigin.Begin);
clonedObject = formatter.Deserialize(stream);
}
return clonedObject;
}
[Serializable]
或实现了ISerializable
,则可以进行往返序列化以创建完全相同的副本。对于[DataContract]
也是同样适用的。ICloneable
接口,那么您只需调用Clone()
方法即可。public static class ExtensionMethods
{
public static T DeepCopyV2<T>(this T source)
{
var jsonString = JsonConvert.SerializeObject(source);
var newObject = JsonConvert.DeserializeObject<T>(jsonString);
return newObject;
}
}
并像这样使用它:
var newObj = obj.DeepCopyV2();