【问题标题】:Adding a clone of an object to a list in c# (prevent modification from outside)在c#中将对象的克隆添加到列表中(防止从外部修改)
【发布时间】:2014-04-26 21:28:21
【问题描述】:

我有一个像'obj1' 这样的对象,我想将它添加到列表中。我可以通过 list1.add(obj1) 添加它。现在,一旦我更新 obj1,我列表中的对象也会更新! (我知道我在这里处理引用)

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

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

提前致谢!

【问题讨论】:

  • 在将它插入列表后创建一个新的 obj1 或使用克隆 (ICloneable) 或尽可能使用 ValueType。

标签: c# reference pass-by-reference


【解决方案1】:

C# 语言不支持对象的克隆。因此,如果 obj1 不是值对象(即结构),则不能这样做。注意:有可能实现ICloneable,但是,its use is not advised

我在另一个项目中使用的一种方法是使用AutoMapper 在插入列表之前创建对象的副本。示例:

MyType copy = Mapper.DynamicMap(obj1);
list.Add(copy);

请仅对值持有者类型使用该方法,尤其是对于实现 IDisposable 或类似内容的类型。

【讨论】:

    【解决方案2】:

    我找到了一种不使用 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());
    

    希望这会有所帮助 =]

    【讨论】:

      【解决方案3】:

      根据我从 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 是受保护的方法,因此扩展方法不起作用。为什么要保护它?我不知道,但如果我不得不猜测,那是因为有一个很好的理由说明你不应该在任何你喜欢的地方克隆对象。

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

      【讨论】:

        猜你喜欢
        • 2019-03-02
        • 2015-06-27
        • 2011-02-04
        • 1970-01-01
        • 1970-01-01
        • 2020-06-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多