这个IClonable实现有问题吗?

3

我没有编写过C#程序,但我的儿子问我这个实现是否有问题。

public class Person : A, IClonable {
....

    public object Clone() {
       return this;
    }
}

我的直觉告诉我这是错误的,因为这个Clone()方法并没有返回任何新对象。我认为Clone()方法应该创建一个新对象或调用创建新对象的方法,然后返回它。这就是我对我儿子说的,但由于我没有进行过任何C#编程,我变得不确定了。能否有人对此作出解释。


1
你是对的:该方法应该创建一个新对象。 - sloth
5个回答

4

我的直觉告诉我这是错误的,因为这个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#中要实现ICloneable接口?


3

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

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

如果现在 Clone() 方法的编写者返回了 this,或者其他人在使用此代码时依赖于返回值作为原始对象的副本,并且进行了一些未在原始对象上进行过的修改,则需要跟踪错误。


2

阅读MSDN并查看这些示例

我认为你是正确的 - 你不会创建新对象,因此如果想要克隆并更改对象 - 他将更改原始对象,这不是预期的结果。


那不是对 IClonable 的引用。 - Emond

1
请注意,IClonable文档没有指定深度或浅层复制。
它只是指定应该进行复制。而这个实现没有。

1
尝试克隆对象,请使用以下方法。

方法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();
    }
}

方法二:
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;
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接