这个IClonable实现有什么问题吗?

本文关键字:问题 什么 IClonable 实现 这个 | 更新日期: 2023-09-27 17:50:53

我没有在c#中编程,但是我的儿子问我这个实现是否有什么问题

public class Person : A, IClonable {
....
    public object Clone() {
       return this;
    }
}

我的直觉是,这是错误的,因为这个Clone()方法实现不返回任何新对象。我认为Clone()方法应该创建一个新对象或调用一个创建新对象然后返回它的方法。这就是我对儿子说的话,但没有做过任何c#编程,我变得不确定。有谁能解释一下吗

这个IClonable实现有什么问题吗?

我的直觉是,这是错误的,因为这个Clone()方法实现不返回任何新对象

那种感觉不会欺骗你。如果要创建一个对象的副本,则需要创建一个新对象。否则,它只是相同的引用,这个实现是毫无意义和误导的。

考虑你的类有一个StringProperty:

Person p1 = new Person{ StringProperty = "Foo" };
Person p2 = (Person)p1.Clone();
p2.StringProperty = "Bah";
Console.Write(p1.StringProperty); // "Bah"

你可以看到,即使我改变了p2的属性,我也会修改其他实例的StringProperty,因为它们实际上是相同的。

你需要这样写:

public object Clone() {
    Person p2 = new Person();
    p2.StringProperty = this.StringProperty;
    // ...
    return p2;
}

虽然我更喜欢创建一个不同的方法Copy,而不是因为它往往不清楚Clone做什么。甚至微软也不建议实现ICloneable

为什么我要在c#中实现iclonable ?

接口是契约。如果你的类实现了iclonable,它承诺:

支持克隆,它创建一个与现有实例值相同的类的新实例

现在,如果Clone() { return this; }的作者,或使用此代码的任何人,依赖于的返回值是原始的克隆,并进行了一些可能未对原始对象进行的修改,那么您就有一个bug需要跟踪。

阅读MSDN并检查此示例

我认为你是对的-你不创建新的对象,所以如果一个人想克隆和改变对象-他会改变原来的对象,这不是预期的

请注意,IClonable文档没有指定深拷贝或浅拷贝。

它只是指定它应该复制。而这个实现没有。

要克隆对象,请尝试此操作。

方法1:

public class Person : ICloneable
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public Address PersonAddress { get; set; }
    public object Clone()
    {
        Person newPerson = (Person)this.MemberwiseClone();
        newPerson.PersonAddress = (Address)this.PersonAddress.Clone();
        return newPerson;
    }
}
public class Address : ICloneable
{
    public int HouseNumber { get; set; }
    public string StreetName { get; set; }
    public object Clone()
    {
        return this.MemberwiseClone();
    }
}
方法2:

public class Person : ICloneable
{
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public Address PersonAddress { get; set; }
    public object Clone()
    {
        object objResult = null;
        using (MemoryStream ms = new MemoryStream())
        {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, this);
            ms.Position = 0;
            objResult = bf.Deserialize(ms);
        }
        return objResult;
    }
}
方法3:
public class Person : ICloneable
    {
        public string LastName { get; set; }
        public string FirstName { get; set; }
        public Address PersonAddress { get; set; }
        public object Clone()
        {
            var objResult = new Person();
            objResult.LastName = this.LastName;
            objResult.FirstName = this.FirstName;
            objResult.PersonAddress = new Address();
            objResult.PersonAddress.HouseNumber = this.PersonAddress.HouseNumber;
            objResult.PersonAddress.StreetName = this.PersonAddress.StreetName;
            return objResult;
        }
    }