#c# #generics #collections #covariance #type-constraints
#c# #обобщения #Коллекции #ковариация #ограничения типа
Вопрос:
Я пытаюсь сделать что-то на C #, что довольно просто в Java, используя ограничение по типу подстановочных знаков. Я попытался свести его только к Java-коду, необходимому для иллюстрации проблемы (компиляции):
public abstract class ParentClass {
public abstract SomeBindingList<? extends ParentClass> parentList();
}
public class ChildClass extends ParentClass {
private SomeBindingList<ChildClass> myList;
public ChildClass() {
// this could load from/bind to a database
myList = new SomeBindingList<ChildClass>();
}
public SomeBindingList<? extends ParentClass> parentList() {
return myList;
}
}
Возможно, мне нужно подчеркнуть следующую строку, поскольку кто-то пометил это как дубликат:
SomeBindingList
является сторонним BindingList
, поэтому я не могу его изменить. Он параметризован и не может быть заменен непараметризованной версией.
Проблема, конечно, заключается в том, как реализовать parentList()
метод в ChildClass
, чтобы возвращать список, который можно использовать как список ParentClass
объектов.
Похоже, что должен быть какой-то способ использовать where
ключевое слово для предоставления ограниченного типа в C #, но я не могу заставить его работать (по крайней мере, синтаксически) с классом, который уже расширяет другой класс, т. Е. ChildClass
, И, похоже, нет способа параметризовать только возвращаемое значениеметод (или свойство).
Я мог бы создать новый список и поместить все ChildClass
элементы в новый список как ParentClass
элементы, но (помимо того, что он запутанный) Я боялся, что это повлияет на поведение SomeBindingList
.
Я не эксперт по C #, поэтому я уверен, что кто-то, более знакомый с языком, знает ответ. Спасибо!
@CodeCaster — я перепробовал много вариантов кода C # (это не компилируется, и я не могу найти вариант, который это делает):
public abstract class ParentClass {
public abstract List<T> parentList<T>() where T : ParentClass;
}
public class ChildClass {
public List<ChildClass> myList;
public ChildClass() {
myList = new List<ChildClass>();
}
public override List<T> parentList<T>() where T : ParentClass {
return myList;
}
}
Я пробовал параметризацию ChildClass<T>
, но это просто вызывает генерацию a List<ChildClass<T>>
, которая не является List<T>
Комментарии:
1. Можете ли вы затем показать код, который вы написали, и какие проблемы у него есть?
2. @StriplingWarrior — я думаю, что ваше решение также было хорошим и может быть полезным для других, если вы также захотите опубликовать его здесь. Если бы я сам писал код с нуля, я бы, вероятно, попробовал это. Приветствия!
Ответ №1:
Я думаю, что ваша проблема здесь связана с желаемой совместимостью отношений между иерархией наследования общего стороннего SomeBindingList<T>
класса и иерархией типов, используемых в качестве параметров.
Во-первых, позвольте мне дать вам код, который будет компилироваться:
public interface ISomeBindingList<out T>
{
}
public abstract class ParentClass
{
public abstract ISomeBindingList<ParentClass> parentList();
}
public class ChildClass : ParentClass
{
private ISomeBindingList<ChildClass> myList;
public ChildClass()
{
// this could load from/bind to a database
// myList = new SomeBindingList<ChildClass>(); // <-- we need to figure out this
}
public override ISomeBindingList<ParentClass> parentList()
{
return myList;
}
}
C # не предоставляет сопоставление общих типов для классов. Но это относится и к интерфейсам. Вам придется мыслить нестандартно и реализовать тривиальный адаптер для вашего стороннего SomeBindingList<T>
разработчика, который реализует только те поднятые элементы, которые совместимы с различными вариантами, то есть: те элементы, которые T
встречаются только в качестве выходных данных.
Например, предполагая SomeBindingList<T>
, что содержит метод T Get()
, вы должны перенести этот элемент в интерфейс адаптера и создать тривиальную реализацию адаптера.
Это был бы полный код:
public interface ISomeBindingList<out T>
{
T Get();
}
public class SomeBindingListAdapter<T> : SomeBindingList<T>, ISomeBindingList<T>
{
}
public abstract class ParentClass
{
public abstract ISomeBindingList<ParentClass> parentList();
}
public class ChildClass : ParentClass
{
private ISomeBindingList<ChildClass> myList;
public ChildClass()
{
// this could load from/bind to a database
myList = new SomeBindingListAdapter<ChildClass>();
}
public override ISomeBindingList<ParentClass> parentList()
{
return myList;
}
}
Комментарии:
1. Большое спасибо! Я не знал этого об интерфейсах. Это хорошо работает в моем случае, когда я работаю с уже существующим кодом. Чем меньше я могу это изменить, тем лучше, и это означает, что мне не нужно параметризовать классы, что потребовало бы изменений во всем коде. Приветствия!