How to use ICloneable <T> when T is List <T>?

I have the following:

public class InstanceList : List<Instance> {} 

I would like to make it cloneable. Following the example here: Why is there no ICloneable <t>?

I tried the following:

  public interface ICloneable<T> : ICloneable Where T : ICloneable<T> { new T Clone(); } public class InstanceList : List<Instance>, ICloneable<List<Instance>> {} 

But I get a compiler error. The error message states that List<Instance> must be convertible to ICloneable<List<Instance>> order to use the T parameter in the general ICloneable<T> interface.

What am I missing here?

+4
source share
4 answers

You cannot do this because you cannot define a List<T> yourself. You could only do this if you could declare your own List<T> due to the way you restricted ICloneable<T> . Since List<T> does not really implement ICloneable<T> , instead you will have to have type T instead of the InstanceList that you control.

Here's how you implement it:

 public class InstanceList : List<Instance>, ICloneable<InstanceList> { public InstanceList Clone() { // Implement cloning guts here. } object ICloneable.Clone() { return ((ICloneable<InstanceList>) this).Clone(); } } public class Instance { } public interface ICloneable<T> : ICloneable where T : ICloneable<T> { new T Clone(); } 

Of course, there is another alternative that you could make. You can extend your generics a bit to create a CloneableList<T> :

 public class CloneableList<T> : List<T>, ICloneable<CloneableList<T>> { public CloneableList<T> Clone() { throw new InvalidOperationException(); } object ICloneable.Clone() { return ((ICloneable<CloneableList<T>>) this).Clone(); } } public interface ICloneable<T> : ICloneable where T : ICloneable<T> { new T Clone(); } 

And if you really want a fantasy, create something that will limit T to ICloneable. Then you can implement ICloneable in the Instance class and everything you want to include in the ICloneable<T> list, thus handling each CloneableList<T> in the same way, avoiding another implementation of ICloneable<T> for each cloning list you want to create.

 public class CloneableList<T> : List<T>, ICloneable<CloneableList<T>> where T : ICloneable { public CloneableList<T> Clone() { var result = new CloneableList<T>(); result.AddRange(this.Select(item => (T) item.Clone())); return result; } object ICloneable.Clone() { return ((ICloneable<CloneableList<T>>) this).Clone(); } } public interface ICloneable<T> : ICloneable where T : ICloneable<T> { new T Clone(); } 
+4
source

The problem is your general restriction where T : IClonable<T> . Since you are "instantiating" your interface as ICloneable<List<Instance>> , List<Instance> is your T , and so the general restriction translates to where List<Instance> : IClonable<List<Instance>> . List<Instance> does not comply with this restriction.

Perhaps you are trying to do something like this:

 public interface ICloneableList<T> : ICloneable where T : ICloneable { } 
+2
source

To add to other good answers already there - when you clone, you expect to get an identical copy, right? Therefore, instead of:

 public class InstanceList : List<Instance>, ICloneable<List<Instance>> {} 

Actually it should not be:

 public class InstanceList : List<Instance>, ICloneable<InstanceList> {} 

That way you also won't get compiler errors.

+1
source

I don’t think you can really do what you want. Although it is useful not to require an argument of type ICloneable <T> to implement ICloneable <T>, I do not think that the List <T> class can be very well extended to support cloning, since it does not provide any means to detach or duplicate an array that contains all data elements, does not allow subclasses to access this array and does not allow the subclass to override sufficient virtual methods to make the array inappropriate. Although cloning methods should start by using a MemberwiseClone object (to ensure that the cloned object is the same type as the original), there would be no guaranteed way to force the newly cloned list to create a new array to store its objects without breaking the old one.

The closest I can suggest to do what you want is to define an ICloneableList <T> that inherits from IList <T> and ICloneable <Tist β†’ and define a class CloneableList that implements this by packing the list. Cloning A CloneableList should create a new List <T> with elements copied from the old, which can be executed using the appropriate constructor for the new list.

0
source

All Articles