Для сценария, такого как:
public interface IAnimal
{
}
public interface IGiraffe : IAnimal
{
}
public interface IQuestionableCollection : IEnumerable<IAnimal>
{
void SomeAction();
}
public interface IQuestionableCollection<out T> : IQuestionableCollection, IEnumerable<T>
where T : IAnimal
{
}
public class QuestionableCollection<T> : IQuestionableCollection<T>
where T:IAnimal
{
// Implementation...
}
Компилятор будет генерировать ошибку:
'IQuestionableCollection<T>' cannot implement both 'System.Collections.Generic.IEnumerable<IAnimal>' and 'System.Collections.Generic.IEnumerable<T>' because they may unify for some type parameter substitutions
И это имеет смысл, есть действительно двусмысленность между двумя интерфейсами, которые С# не может решить, если только он не использует ограничение типа, которое не соответствует спецификации языка, поскольку @ericlippert объясняет .
Мой вопрос: как мне реализовать что-то с этим же эффектом?
Похоже, я должен быть в состоянии выразить, что коллекция перечислима для базового интерфейса. (Я хотел бы предоставить набор методов, которые можно было бы использовать, не зная конкретного типа, а также сделать некоторые API/код отражения более чистыми, поэтому я хотел бы сохранить базовую коллекцию как универсальную, если вообще возможно, в противном случае не было бы необходимости в двух интерфейсах.)
Единственная реализация, которую я могу придумать, заключается в следующем:
public interface IQuestionableCollectionBase
{
void SomeAction();
}
public interface IQuestionableCollection : IQuestionableCollectionBase, IEnumerable<IAnimal>
{
}
public interface IQuestionableCollection<out T> : IQuestionableCollectionBase, IEnumerable<T>
where T : IAnimal
{
}
public class QuestionableCollectionBase<T> : IQuestionableCollection
where T : IAnimal
{
protected List<T> _items = new List<T>();
public void SomeAction() { }
IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); }
IEnumerator<IAnimal> IEnumerable<IAnimal>.GetEnumerator() { return ((IEnumerable<IAnimal>)_items).GetEnumerator(); }
}
public class QuestionableCollection<T> : QuestionableCollectionBase<T>, IQuestionableCollection<T>
where T : IAnimal
{
public IEnumerator<T> GetEnumerator() { return ((IEnumerable<T>)_items).GetEnumerator(); }
}
Обратите внимание, что мне пришлось перемещать любые методы, которые я хотел бы использовать на обоих интерфейсах, для базового метода и иметь два уровня реализации для самого класса - похоже, что я прыгаю через достаточно обручей здесь, что я что-то не хватает...
Как это реализовать?