Интегрированные интерфейсы
Я часто хотел создать список объектов, где каждый объект должен реализовывать ряд интерфейсов. Например, я хотел бы сделать что-то похожее на следующее:
List<T> where T : IConvertible, IComparable _myList;
Еще один вариант, который я рассматривал, - создать третий интерфейс, который реализует эти два, чтобы любой объект, реализующий эти два интерфейса, по своей сути реализует мои.
public interface IConvertibleAndComparable
: IConvertible, IComparable { }
List<IConvertibleAndComparable> _myList;
С этим я бы мог добавить любой объект, который реализует как IConvertible
, так и IComparable
, включая double
и int
, а также мои собственные объекты. Явно реализовать IConvertibleAndComparable
не требуется, поскольку он не добавляет никаких новых функциональных возможностей за пределы интерфейсов в наследованиях.
Я понимаю, что первый фрагмент является незаконным, а второй, хотя и законным, не делает то, что я хочу. Можно ли достичь того, что я пытаюсь сделать? Если нет, будет ли кто-нибудь из них быть кандидатом на будущую функцию С#?
(Примечание. Это было бы законным приложением для пустых интерфейсов.)
Edit
В более общем смысле я хотел бы выполнить одно из следующих действий:
private MyGenericClass<T> where T : IA, IB, ... _myClass;
где я могу объявить все ограничения на T
, которые мне нужны, или
public interface IMyCombinedInterface : IA, IB, ... {}
private MyGenericClass<IMyCombinedInterface> _myClass;
где любой тип, реализующий IA
, IB
и ...
по своей сути (или неявно) реализует IMyCombinedInterface
(только если IMyCombinedInterface
явно не объявляет новую функциональность).
Ответы
Ответ 1
В качестве обходного пути вы можете сделать своего рода суперпозиционную оболочку и сохранить ее в списке. Посмотрите здесь для этой идеи.
В ваш пример вы можете сделать:
public class Junction
{
public IConvertible Convertible { get; private set; }
public IComparable Comparable { get; private set; }
private Junction() { }
public static Junction Create<T>(T value) where T : IConvertible, IComparable
{
return new Junction
{
Convertible = value,
Comparable = value
};
}
}
И затем добавьте Junction
в свой список:
var l = new List<Junction>();
l.Add(Junction.Create(1));
Ответ 2
Во время работы над другим проектом у меня возникла идея еще одного обходного пути. Хотя это может не сработать для примера, который я опубликовал, он может работать для первоначального намерения вопроса, а именно для создания комбинационного интерфейса для IEnumerable<T>
и INotifyCollectionChanged
(как отметил @DanielHilgarth). Обходной путь выглядит следующим образом:
Создайте пустой интерфейс, который реализует комбинацию необходимых вам интерфейсов.
public interface INotifyingEnumerable<T> :
IEnumerable<T>,
INotifyCollectionChanged
{
}
Создайте новый класс, который наследует от класса, реализующего оба из них, и реализует новый интерфейс.
public class MyObservableCollection<T> :
ObservableCollection<T>,
INotifyingEnumerable<T>
{
}
Теперь вы можете использовать интерфейс INotifyingEnumerable<T>
как тип свойства, который использует вашу реализацию.
Причина, по которой это не совсем касается первоначальных требований, однако, заключается в том, что она не позволяет напрямую назначать ObservableCollection<T>
. Функция, запрошенная в исходном сообщении, позволит это.