Why Should I Implement Icloneable in C#

Why should I implement ICloneable in c#?

You shouldn't. Microsoft recommends against implementing ICloneable because there's no clear indication from the interface whether your Clone method performs a "deep" or "shallow" clone.

See this blog post from Brad Abrams back in 2003(!) for more information.

Should I Implement ICloneable?

A problem with implementing ICloneable is that a storage location (field, variable, array slot, etc.) of a mutable reference type may be used to encapsulate identity, mutable state, both, or neither, but neither .NET nor any of its languages include any standard convention to indicate which of the above any given storage location is supposed to encapsulate.

If a field Foo1 encapsulates identity but not mutable state, then George.Clone().Foo1 should refer to the same instance as George.Foo1.

If a field Foo2 encapsulates mutable state but not identity, then George.Clone().Foo2 should refer to a new object which is initialized to have the same state as George.Foo2.

If a field Foo3 encapsulates neither mutable state nor identity [i.e. only immutable state other than identity], then George.Clone().Foo3 may refer to George.Foo3, a new object with the same state, or any other convenient object with the same state.

If a field Foo4 encapsulates both mutable state and identity, instances of the type cannot be meaningfully cloned using a Clone method.

If there were different storage location types for things that encapsulate identity, mutable state, both, or neither, there would be little for a deep- versus shallow distinction, since any reference-type field or other storage location encapsulated by a type should be cloned by recursively applying the above rules (note that for properly-constructed objects this cannot result in endless recursion, since two objects cannot meaningfully encapsulate each others' mutable state without at least one of them also encapsulating the other's identity). Unfortunately, because no such distinctions exist in the type system, there's no practical solution except to either implement ad-hoc cloning methods, or else implement a cloning method which uses attributes to decide what it should do, and uses hard-coded behavior for built-in .NET types which don't include any special indicators.

ICloneable Interface

  clonedCloner.MyContent = MyContent.Clone();

The Content class does not implement ICloneable so this statement cannot compile. You are getting a bit lost, I can not see which implementation of Cloner you actually used and how this class has anything to do with Person.

Do note that you did not actually test whether you got a deep clone. You only tested for the shallow clone case by checking that the collection wasn't being modified. A deep clone test would, say, alter a property of Mick and check that the original collection still has an unmodified Mick. Which is really the meaning of "deep". Which is okay in your code, you however lose elegance points for using MemberwiseClone(), it doesn't do anything useful and is the opposite of deep cloning.

Frankly, the book isn't teaching you very good practices. The ICloneable interface narrowly escaped being deprecated and should be avoided. It is a broken interface, it doesn't allow the caller to specify whether a deep or a shallow copy is desired. Too often, it is implemented as a shallow copy, because it is cheap and easy, while the caller really wanted a deep copy. Producing a nasty bug that is pretty hard to diagnose.

If you want to support deep-cloning then just add a Person DeepClone() method to your class. Now it is explicit and type-safe.

Don't dwell on this, move on in the book. Do consider finding a better one.

How to correct implement ICloneable in a tree hierarchy rooted by an abstract class?

Since your Student class inherits the properties/fields from the base class (Person), it is not necessary to clone the person object.

The solution is to not implement the Clone() method within the abstract base class, but instead make it abstract and force the implementation in any sub-classes which inherit from it. In order to clone, you can simply instantiate a new instance of the Student class and populate the base properties using a clone constructor. See my example. I'm not sure if this helps in any way.

class Program
{
static void Main(string[] args)
{
Student studentA = new Student(1000, "Defense Against the Dark Arts", "Harry", "Potter", 25);
Student studentB = (Student)studentA.Clone();
}
}

public abstract class Person : ICloneable
{
public string FirstName { get; set; }
public string Surname { get; set; }

private int SomePrivateVariable { get; set; }

public Person()
{

}

public Person(string firstName, string surname, int privateVariableDefault)
{
this.FirstName = firstName;
this.Surname = surname;
this.SomePrivateVariable = privateVariableDefault;
}

public Person(Person original)
{
this.FirstName = original.FirstName;
this.Surname = original.Surname;
this.SomePrivateVariable = original.SomePrivateVariable;
}

public abstract object Clone();
}

public sealed class Student : Person
{
public int StudentId { get; set; }
public string CourseTitle { get; set; }

public Student()
{

}

//Constructor with all the fields, passed down to the base class
public Student(int studentId, string courseTitle, string firstName, string surname, int baseVariableDefault)
: base(firstName, surname, baseVariableDefault)
{
this.StudentId = studentId;
this.CourseTitle = courseTitle;
}

//A clone constructor which takes an object of the same type and populates internal
//and base properties during construction
public Student(Student original)
: base(original)
{
this.FirstName = original.FirstName;
this.Surname = original.Surname;
this.StudentId = original.StudentId;
this.CourseTitle = original.CourseTitle;
}

public override object Clone()
{
Student clone = new Student(this);
return clone;
}
}

Why no ICloneable T ?

ICloneable is considered a bad API now, since it does not specify whether the result is a deep or a shallow copy. I think this is why they do not improve this interface.

You can probably do a typed cloning extension method, but I think it would require a different name since extension methods have less priority than original ones.

Cloning an array of objects which implement ICloneable

You can use Linq for that:

return MyStuffObjs.Select(item => (MyStuff)item.Clone()).ToArray();

You can even create a helper method like this

public static class MyExtensions
{
public static T[] DeepClone<T>(this T[] source) where T : ICloneable
{
return source.Select(item => (T)item.Clone()).ToArray();
}
}

and use it as follows

return MyStuffObjs.DeepClone();

What is the use of IClonable interface in .NET?

Well, not much really. It earned a special mention in the Framework Design Guidelines as an interface to avoid.

Do not implement ICloneable. There
are two general ways to implement
ICloneable, either as a deep, or
non-deep copy. Deep-copy copies the
cloned object and all objects
referenced by the object, recursively
until all objects in the graph are
copied. A non-deep copy (referred to
as ‘shallow’ if only the top level
references are copied) may do none, or
part of a deep copy. Because the
interface contract does not specify
the type of clone performed, different
classes have different
implementations. A consumer cannot
rely on ICloneable to let them know
whether an object is deep-cloned or
not.

There has been discussion in the past about obsoleting it. I am not sure what ever came of that, but the framework designers have admitted that it was probably a mistake.

If you want to support cloning then I would create and implement separate interfaces IDeepCopy and IShallowCopy or the like.

Why does OracleParameter implement ICloneable but doesn't provide Clone()?

In .NET you can explicitly implement interface members by using the following syntax:

object System.IClonable.Clone()
{
}

As a result you can only use the method by explicitly casting to the expected interface.

Also see
http://msdn.microsoft.com/en-us/library/system.data.oracleclient.oracleparameter.system.icloneable.clone(VS.85).aspx

Is there anything wrong with this IClonable implementation

My gut feeling is that it is wrong because this Clone() method
implementation does not return any new object

That feeling does not deceive you. You need to create a new object if you want to create a copy of it. Otherwise it's just the same reference and this implemenntation is pointless and misleading.

Consider that your class has a StringProperty:

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

You see that even if i change the property on p2 i also modify StringProperty of the other instance since it's actually the same.

So you need something like this:

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

Although i prefer to create a different method Copy instead since it's often not clear what Clone does. Even Microsoft recommends against implementing ICloneable.

Why should I implement ICloneable in c#?



Related Topics



Leave a reply



Submit