我有一个像'obj1'
这样的对象我想添加到列表中。我可以只添加list1.add(obj1)
。现在我更新obj1
后,我列表中的对象也在更新! (我知道我在这里处理参考资料)
我的要求要求修改obj1
并再次将其添加到列表中!我没有两个不同的对象,而只有一个,因为对于它们两者而言,引用是相同的 - obj1
。
有什么方法可以修改这个obj1
并将其添加到列表中并且仍然不会丢失旧的列表吗?任何变通办法都非常有帮助!
提前致谢!
答案 0 :(得分:7)
C#语言不支持克隆对象。因此,如果obj1
不是值对象(即结构),则不能这样做。注意:有可能实施ICloneable
,its use is not advised。
我在另一个项目中使用的一种方法是在插入列表之前使用AutoMapper创建对象的副本。例如:
MyType copy = Mapper.DynamicMap(obj1);
list.Add(copy);
请仅对价值持有人类型使用该方法,尤其不适用于实施IDisposable
或类似内容的类型。
答案 1 :(得分:3)
我找到了一种方法来完成AutoMapper。虽然AutoMapper看起来像一个很棒的工具,但我无法在需要Net2.0 / Mono的项目中使用它。
您可以使用序列化程序创建对象的副本/克隆。我使用json.NET因为我已经在我的项目中使用它,但我想其他库也可以工作。基本上,您将对象序列化为字符串,然后从该字符串创建一个新对象,因为该字符串未绑定到原始对象,您将获得一个全新的对象。
以下是使用json.net的代码示例:
List<SomeObject> list1 = new List<SomeObject>();
SomeObject obj1 = new SomeObject(params, etc);
string data = JsonConvert.SerializeObject(obj1);
SomeObject obj2 = JsonConvert.DeserializeObject<SomeObject>(data);
list1.Add(obj2);
你甚至可以将最后三行缩短为类似的东西:
list1.Add(JsonConvert.DeserializeObject<SomeObject>(JsonConvert.SerializeObject(obj1)));
您可以编写一个函数/方法来为您执行此操作。由于我正在创建自己的对象类型,因此我在对象中添加了一个类似于此的对象:
public ItemInputData copyOf()
{
string data = JsonConvert.SerializeObject(this);
ItemInputData copy = JsonConvert.DeserializeObject<ItemInputData>(data);
return copy;
}
将列表添加到列表中的代码如下所示:
list1.Add(item.copyOf());
希望这有助于=]
答案 2 :(得分:0)
根据我从C#6.0 Cookbook中所读的内容,执行此操作的最佳方法是创建自己的ShallowClone和DeepClone接口,然后实现它们。不建议使用ICloneable的原因是由于对ICloneable是否创建DeepClone或ShallowClone感到困惑,因此,如果Microsoft不起作用,请改用自己的界面。
ShallowClone正在使用具有相同引用的所有属性重新创建对象(两个不同的对象引用相同的属性)
DeepClone正在使用新属性重新创建对象。
要进行ShallowClone,请执行以下操作:
public ShallowClone ShallowCopy() => (ShallowClone)this.MemberwiseClone();
对于DeepClone:
public DeepClone DeepCopy()
{
BinaryFormatter BF = new BinaryFormatter();
MemoryStream memStream = new MemoryStream();
BF.Serialize(memStream, this);
memStream.Flush();
memStream.Position = 0;
return (DeepClone)BF.Deserialize(memStream);
}
直接从书中被盗,因此所有功劳都归功于此。我只是记得这是在C#中“应该”完成的方式。不过,也许还有更好的方法,尤其是当我们现在使用C#8.0时。
您可以编写自己的ShallowClone和DeepClone方法,并分配每个属性或创建新属性,但这很乏味,因此上述方法如此有用。
因此,您的想法是在要克隆的对象上实现这些接口,然后使用这些方法。
我当时正在考虑制作这些扩展方法,但这是行不通的。我的想法是这样的:
public static class CloningExtention
{
public static T ShallowClone(this T obj) => (T)obj.MemberwiseClone(); // Doesn't work
public static T DeepClone(this T obj)
{
BinaryFormatter BF = new BinaryFormatter();
MemoryStream memStream = new MemoryStream();
BF.Serialize(memStream, this);
memStream.Flush();
memStream.Position = 0;
return (T)BF.Deserialize(memStream);
};
}
但是MemberwiseClone是受保护的方法,因此扩展方法不起作用。为什么要保护它?我不知道,但是如果我不得不猜测,那是因为有一个很好的理由,为什么你不应该在任何你喜欢的地方克隆对象。
但是,我仍然想演示它,所以您知道不要这样做。如果有人知道为什么要保护此方法,请告诉我。