I have the following:
public class InstanceList : List<Instance> {}
I would like to make this cloneable. Following the example here: Why 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>>
in order to use parameter T in the generic interface
ICloneable<T>
.
What am I missing here?
ICloneable interface it implements Clone() method which performs a deep copy operation on objects of that class.
The ICloneable interface enables you to provide a customized implementation that creates a copy of an existing object. The ICloneable interface contains one member, the Clone method, which is intended to provide cloning support beyond that supplied by Object. MemberwiseClone.
You can't do this, because you can't define List<T>
yourself. You would only be able to do this if you could declare your own List<T>
because of the way you've constrained ICloneable<T>
. Since List<T>
truly doesn't implement ICloneable<T>
, you're going to have to have the type of T be InstanceList instead, which you do have control over.
Here's how you would 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 you could do. You could widen your generics a little bit, to create a CloneableList<T>
type:
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 to get fancy, create something that restricts T to ICloneable. Then you could implement ICloneable on the Instance class, and anything else you want to include in an ICloneable<T>
list, thus treating every CloneableList<T>
in the exact same way, avoiding a different implementation of ICloneable<T>
for each and every cloneable 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();
}
The problem is your generic constraint where T : IClonable<T>
. Because you're "instantiating" your interface as ICloneable<List<Instance>>
, List<Instance>
is your T
, and so the generic constraint translates to where List<Instance> : IClonable<List<Instance>>
. List<Instance>
does not fulfill that constraint.
Perhaps you're trying to do something like this:
public interface ICloneableList<T> : ICloneable where T : ICloneable
{
}
To add to the other good answers already there - when you clone, you expect to get an identical copy back, right? So instead of:
public class InstanceList : List<Instance>, ICloneable<List<Instance>> {}
Shouldn't it actually be:
public class InstanceList : List<Instance>, ICloneable<InstanceList> {}
That way you will also get no compiler errors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With