当我执行以下操作时...对人物b做的任何事情都会修改人物a(我认为这样做会从人物a克隆人物b)。我也不知道如果更改Person a将在链接后更改Person b。由于我的代码现在,我只能在一个方向看到这个。
Person a = new Person() { head = "big", feet = "small" };
Person b = a;
b.head = "small"; //now a.head = "small" too
现在,如果我这样做了。人a变得完全分开。
Person b = new Person() { head = a.head, feet = a.feet };
现在,将此行为与C#中的其他内容进行比较时,这种方法很有意义。但是,对于大型物体,这可能会非常烦人。
有没有办法简化这个?
如:
Person b = a.Values;
答案 0 :(得分:62)
您正在寻找克隆的内容。您需要实施IClonable然后进行克隆。
示例:
class Person() : ICloneable
{
public string head;
public string feet;
#region ICloneable Members
public object Clone()
{
return this.MemberwiseClone();
}
#endregion
}
然后您可以简单地调用Clone方法来执行 ShallowCopy (在此特定情况下也是 DeepCopy )
Person a = new Person() { head = "big", feet = "small" };
Person b = (Person) a.Clone();
您可以使用Object类的MemberwiseClone方法进行克隆。
答案 1 :(得分:38)
有没有办法简化这个?
不,不是真的。您需要创建一个新实例,以避免原始文件影响“副本”。有几种选择:
如果您的类型是struct
,而不是class
,则会按值复制(而不是仅仅复制对实例的引用)。这将给你它描述的语义,但有许多其他副作用,往往不太理想,不建议任何可变类型(这显然是,或这不会是一个问题!)< / p>
在您的类型上实施“克隆”机制。这可以是ICloneable
,甚至只是一个构造函数,它接受一个实例并从中复制值。
使用反射,MemberwiseClone或类似方法复制所有值,因此您不必编写代码来执行此操作。这有潜在的问题,特别是如果你有包含非简单类型的字段。
答案 2 :(得分:13)
我使用AutoMapper。它的工作原理如下:
Mapper.CreateMap(typeof(Person), typeof(Person));
Mapper.Map(a, b);
现在,人a具有人b的所有属性。
另外,AutoMapper也适用于不同的对象。有关详细信息,请查看http://automapper.org
更新:我现在使用这个语法(简单来说 - 真的是CreateMaps在AutoMapper配置文件中):
Mapper.CreateMap<Person, Person>;
Mapper.Map(a, b);
请注意,您不必执行CreateMap将相同类型的一个对象映射到另一个对象,但如果不这样做,AutoMapper将创建一个浅表副本,这意味着如果您更改一个对象,另一个也发生了变化。
答案 3 :(得分:13)
由于MemberwiseClone()方法不公开,我创建了这个简单的扩展方法,以便更容易克隆对象:
public static T Clone<T>(this T obj)
{
var inst = obj.GetType().GetMethod("MemberwiseClone", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
return (T)inst?.Invoke(obj, null);
}
用法:
var clone = myObject.Clone();
答案 4 :(得分:7)
要克隆类对象,可以使用Object.MemberwiseClone方法
只需将此功能添加到您的班级:
public class yourClass
{
// ...
// ...
public yourClass DeepCopy()
{
yourClass othercopy = (yourClass)this.MemberwiseClone();
return othercopy;
}
}
然后执行深度独立副本,只需调用DeepCopy方法:
yourClass newLine = oldLine.DeepCopy();
答案 5 :(得分:6)
a
和b
只是对同一Person对象的两个引用。它们基本上都包含Person
的地址。
有一个ICloneable接口,但相对较少的类支持它。有了这个,你会写:
Person b = a.Clone();
然后,b将完全独立Person
。
您还可以实现复制构造函数:
public Person(Person src)
{
// ...
}
没有内置方法可以复制所有字段。你可以通过反射来实现,但会有性能损失。
答案 6 :(得分:1)
public static T Clone<T>(T obj)
{
DataContractSerializer dcSer = new DataContractSerializer(obj.GetType());
MemoryStream memoryStream = new MemoryStream();
dcSer.WriteObject(memoryStream, obj);
memoryStream.Position = 0;
T newObject = (T)dcSer.ReadObject(memoryStream);
return newObject;
}
答案 7 :(得分:1)
无痛:使用NClone库
Person a = new Person() { head = "big", feet = "small" };
Person b = Clone.ObjectGraph(a);
答案 8 :(得分:1)
没有比这更简单的了:
public SomeClass Clone () {
var clonedJson = JsonConvert.SerializeObject (this);
return JsonConvert.DeserializeObject<SomeClass> (clonedJson);
}
只需将任何对象序列化为JSON字符串,然后反序列化即可。这将进行深度复制...
答案 9 :(得分:0)
你可以这样做:
var jss = new JavaScriptSerializer();
var b = jss.Deserialize<Person>(jss.Serialize(a));
对于深度克隆,您可能需要查看以下答案: https://stackoverflow.com/a/78612/550975
答案 10 :(得分:0)
MemberwiseClone
是其他人建议的进行浅表复制的好方法。但是,它是受保护的,因此,如果要使用它而不更改类,则必须通过反射来访问它。但是反射很慢。因此,如果您打算克隆很多对象,则可能值得缓存结果:
public static class CloneUtil<T>
{
private static readonly Func<T, object> clone;
static CloneUtil()
{
var cloneMethod = typeof(T).GetMethod("MemberwiseClone", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
clone = (Func<T, object>)cloneMethod.CreateDelegate(typeof(Func<T, object>));
}
public static T ShallowClone(T obj) => (T)clone(obj);
}
public static class CloneUtil
{
public static T ShallowClone<T>(this T obj) => CloneUtil<T>.ShallowClone(obj);
}
您可以这样称呼它:
Person b = a.ShallowClone();
答案 11 :(得分:0)
我认为,最好的方法是实现自己的Clone()
方法,如下所示。
class Person
{
public string head;
public string feet;
// Downside: It has to be manually implemented for every class
public Person Clone()
{
return new Person() { head = this.head, feet = this.feet };
}
}
class Program
{
public static void Main(string[] args)
{
Person a = new Person() { head = "bigAF", feet = "smol" };
Person b = a.Clone();
b.head = "notEvenThatBigTBH";
Console.WriteLine($"{a.head}, {a.feet}");
Console.WriteLine($"{b.head}, {b.feet}");
}
}
输出:
bigAf,smol
notEvenThatBigTBH,smol
b
完全独立于a
,因为它不是参考,而是克隆。
希望我能帮上忙!
答案 12 :(得分:0)
这段代码对我有用。执行时间也非常短。
public static void CopyTo(this object Source, object Destination)
{
foreach (var pS in Source.GetType().GetProperties())
{
foreach (var pT in Destination.GetType().GetProperties())
{
if (pT.Name != pS.Name) continue;
(pT.GetSetMethod()).Invoke(Destination, new object[]
{ pS.GetGetMethod().Invoke( Source, null ) });
break;
}
};
}
答案 13 :(得分:-2)
这是因为“Person”是一个类,因此它通过引用传递。 在语句“b = a”中,您只是复制对使用关键字new创建的唯一“Person”实例的引用。
让您正在寻找的行为的最简单方法是使用“值类型”。
只需从
更改Person声明即可class Person
到
struct Person