【问题标题】:Deepclone - object passed to ctor is no longer ==Deepclone - 传递给 ctor 的对象不再是 ==
【发布时间】:2014-12-27 01:19:38
【问题描述】:

查看 !=
我需要那是一个 ==
不只是返回 true - 是同一个对象

如果我更改 MyObj1.MyRepeat,更改也在 MyObj2.MyRepeat
如果我更改 MyObj1Clone.MyRepeat 它不会更改 MyObj2Clone.MyRepeat(或 MyObj1.MyRepeat)

很确定我只需要编写一个 CustomClone 而不是使用这个序列化/反序列化 DeepClone
只是检查 - 还有其他方法吗?

MyRepeatedObj MyRepeat = new MyRepeatedObj("xxx");

MyObj MyObj1 = new MyObj (1, MyRepeat );
MyObj MyObj2 = new MyObj (2, MyRepeat );

//  MyObj1.MyRepeat  == MyObj2.MyRepeat

MyObj MyObj1Clone = DeepClone(MyObj1);
MyObj MyObj2Clone = DeepClone(MyObj2);

//  MyObj1Clone.MyRepeat  != MyObj2Clone.MyRepeat


public static T DeepClone<T>(T obj)
{
    using (var ms = new MemoryStream())
    {
        var formatter = new BinaryFormatter();

        formatter.Serialize(ms, obj);
        ms.Position = 0;

        return (T)formatter.Deserialize(ms);
    }
}

按照 Hans 的建议,我将 GUID 作为 PK 引入并将其用于覆盖 equals
.Equal 返回 true
== 仍然是错误的,因为 DeepCone 创建了单独的对象

public Guid PK { get { return guid; } }
public override bool Equals(Object obj)
{
    // Check for null values and compare run-time types.
    if (obj == null) return false;
    if (!(obj is SearchEnum1MVand)) return false;
    SearchEnum1MVand comp = (SearchEnum1MVand)obj;
    return (comp.PK == this.PK);   // && comp.AndOr == this.AndOr
}
public override int GetHashCode()
{
    return FieldDef.ID;
}

我很抱歉没有在第一篇文章中包含更多细节

public MyRepeatedObj(GabeLib.FieldDefEnum1 FieldDef, GabeLib.enumAndOr paramAndOr)
{
    // the si... are MyObj that I pass the reference with this
    siAll = new SearchItemEnum1(paramAndOr, enumSrchCond.All, FieldDef, this);
    siAllNot = new SearchItemEnum1(paramAndOr, enumSrchCond.Not_All, FieldDef, this);
    siAny = new SearchItemEnum1(paramAndOr, enumSrchCond.Any, FieldDef, this);
    siAnyNot = new SearchItemEnum1(paramAndOr, enumSrchCond.Not_Any, FieldDef, this);

当我序列化/反序列化时,这是 4 种不同的

但我序列化/反序列化 4 MyObj - 我将尝试序列化/反序列化 MyRepeatedObj,然后将 4 MyObj 作为属性

MyRepeatedObj 的 DeepClone 修复了它

SearchEnum1MVand searchEnum1MVand = DeepClone<SearchEnum1MVand>(((SearchItemEnum1)fieldDefSSDrowSelected.SearchItems[0]).SearchEnum1MVand);
Debug.WriteLine(searchEnum1MVand.SIall.SearchEnum1MVand.MVid.ToString());
Debug.WriteLine(searchEnum1MVand.SIany.SearchEnum1MVand.MVid.ToString());
searchEnum1MVand.SIall.SearchEnum1MVand.MVid++;
Debug.WriteLine(searchEnum1MVand.SIall.SearchEnum1MVand.MVid.ToString());
Debug.WriteLine(searchEnum1MVand.SIany.SearchEnum1MVand.MVid.ToString());
Debug.WriteLine(searchEnum1MVand.SIall.EnterOrder.ToString());
Debug.WriteLine(searchEnum1MVand.SIany.EnterOrder.ToString());
Debug.WriteLine(searchEnum1MVand.SIany.SearchEnum1MVand.SIall.EnterOrder.ToString());
searchEnum1MVand.SIall.EnterOrder++;
Debug.WriteLine(searchEnum1MVand.SIall.EnterOrder.ToString());
Debug.WriteLine(searchEnum1MVand.SIany.EnterOrder.ToString());
Debug.WriteLine(searchEnum1MVand.SIany.SearchEnum1MVand.SIall.EnterOrder.ToString());

【问题讨论】:

  • 我的水晶球说你忘记覆盖 GetHashCode()。所以你得到了 Object.GetHashCode() 返回的值。不同的值,因为它们是不同的对象。
  • @HansPassant 我把 override GetHashCode() 放回去,它们仍然不相等。我曾经覆盖 GetHashCode() 和 Equals 并且它有效,但我不能再覆盖 Equals,因为该对象不再具有 PK。
  • 好吧,你肯定做错了,但我们看不到你做错了。无论如何,散列几乎永远不适合主键,它不能保证是唯一的。如果您需要 PK,那么只需将其设为属性即可。 Guid 总是一个好主意。
  • @HansPassant 我没有做错。 MyObj1Clone.MyRepeat MyObj2Clone.MyRepeat 现在具有相同的哈希值,但仍然不相等。我没有说我使用散列作为 PK - 我说对象不再具有自然 PK。 GUID 可能会解决这个问题,但它仍然会留下另一个问题。我将测试 GUID 是否相等,因为这是所述的问题。
  • @CodeCaster 好的,感谢您的反馈。居高临下不是我的本意。我得到 Deserialize() 没有返回相同的对象实例。这就是为什么我说“只是检查”。

标签: .net clone


【解决方案1】:

== 仍然为假,因为 DeepCone 创建了单独的对象

嗯,是的 - 如果它返回相同的对象,它就不是“克隆”!

Deserialization 总是创建新对象。如果您想要一个新的父对象但保留对子对象的引用,那么您需要一个 shallow 克隆。有几个选项可以做到这一点:

  • Clone() 方法添加到调用this.MemberwiseClone();MyObj(您不能在外部调用它,因为它是protected 而不是public
  • 使用反射循环遍历字段和属性。将它们复制到新对象

【讨论】:

  • 请再次阅读问题。对同一对象的引用不再是对同一对象的引用。 MyObj1.MyRepeat == MyObj2.MyRepeat 和 MyObj1Clone.MyRepeat != MyObj2Clone.MyRepeat。愚弄它以返回一个 true 不会使它成为同一个对象,我需要它是同一个对象。编写 MyClone 并没有什么大不了的。我只是向所有以该类作为输入的类添加一个ctor。
  • 好的,是的,我误解了你的问题 - 你想要的是一个 shallow 克隆。
  • 对不起,问题不是很清楚。我可能使用错误的术语,但我认为我仍然需要一个深层副本。我想要一个新的 MyObj1Clone 和 MyObj2Clone 以及新的 MyRepeatedObj,它们都引用了。
  • 是的,您使用的术语错误 - 深层副本也会(递归地)复制子对象的副本,具有相同内部对象的外部对象的副本是浅层副本。
  • 对不起,我要么不明白,要么我仍然使用错误的术语。我也想要所有子对象的全新/新副本。但是我需要 MyObj1Clone.MyRepeat == MyObj2Clone.MyRepeat 是相同的(新)对象,并且序列化/反序列化不会这样做(我明白了)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-01
相关资源
最近更新 更多