Как использовать ICloneable<T>, когда T - это List<T>?
У меня есть следующее:
public class InstanceList : List<Instance> {}
Я хотел бы сделать это клонируемым. Ниже приведен пример: почему нет ICloneable
Я попробовал следующее:
public interface ICloneable<T> : ICloneable Where T : ICloneable<T>
{ new T Clone(); }
public class InstanceList : List<Instance>, ICloneable<List<Instance>> {}
Но я получаю ошибку компилятора. Сообщение об ошибке гласит, что List<Instance>
должен быть конвертируемым в ICloneable<List<Instance>>
для того, чтобы использовать параметр T в универсальном интерфейсе ICloneable<T>
,
Что мне здесь не хватает?
4 ответа
Вы не можете сделать это, потому что вы не можете определить List<T>
сам. Вы сможете сделать это только в том случае, если сможете List<T>
из-за того, как вы ограничены ICloneable<T>
, поскольку List<T>
действительно не реализует ICloneable<T>
вместо этого вам нужно будет иметь тип T быть InstanceList, который вы можете контролировать.
Вот как вы бы это реализовали:
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();
}
Конечно, есть другая альтернатива, которую вы могли бы сделать. Вы можете немного расширить свои дженерики, чтобы создать 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();
}
И если вы действительно хотите стать модным, создайте что-то, что ограничивает T до ICloneable. Тогда вы могли бы реализовать ICloneable в классе Instance и все, что вы хотите включить в ICloneable<T>
список, таким образом, рассматривая каждый CloneableList<T>
точно так же, избегая другой реализации ICloneable<T>
для каждого клонируемого списка, который вы хотите создать.
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();
}
Проблема в вашем общем ограничении where T : IClonable<T>
, Потому что вы "создаете экземпляр" своего интерфейса как ICloneable<List<Instance>>
, List<Instance>
твой T
и поэтому общее ограничение переводится в where List<Instance> : IClonable<List<Instance>>
, List<Instance>
не выполняет это ограничение.
Возможно, вы пытаетесь сделать что-то вроде этого:
public interface ICloneableList<T> : ICloneable where T : ICloneable
{
}
Чтобы добавить к другим хорошим ответам уже там - когда вы клонируете, вы ожидаете получить идентичную копию обратно, верно? Так что вместо:
public class InstanceList : List<Instance>, ICloneable<List<Instance>> {}
Не должно ли это быть на самом деле:
public class InstanceList : List<Instance>, ICloneable<InstanceList> {}
Таким образом, вы также не получите ошибок компилятора.
Я не думаю, что вы действительно можете делать то, что вы хотите. Хотя полезно не требовать аргумент типа ICloneable
Самое близкое, что я могу предложить для того, чтобы делать то, что вам нужно, это определить ICloneableList