将对象的克隆添加到c#中的列表中(防止从外部修改)

时间:2014-03-20 07:24:55

标签: c# reference pass-by-reference

我有一个像'obj1'这样的对象我想添加到列表中。我可以只添加list1.add(obj1)。现在我更新obj1后,我列表中的对象也在更新! (我知道我在这里处理参考资料)

我的要求要求修改obj1并再次将其添加到列表中!我没有两个不同的对象,而只有一个,因为对于它们两者而言,引用是相同的 - obj1

有什么方法可以修改这个obj1并将其添加到列表中并且仍然不会丢失旧的列表吗?任何变通办法都非常有帮助!

提前致谢!

3 个答案:

答案 0 :(得分:7)

C#语言不支持克隆对象。因此,如果obj1不是值对象(即结构),则不能这样做。注意:有可能实施ICloneableits 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是受保护的方法,因此扩展方法不起作用。为什么要保护它?我不知道,但是如果我不得不猜测,那是因为有一个很好的理由,为什么你不应该在任何你喜欢的地方克隆对象。

但是,我仍然想演示它,所以您知道不要这样做。如果有人知道为什么要保护此方法,请告诉我。