Как вы правильно предположили, проблема возникает из-за неясностей, обнаруженных при выводе типа.Когда вы говорите:
class Ark : IEnumerable<Turtle>, IEnumerable<Giraffe>
{ ... }
, а затем вы говорите
Ark ark = whatever;
ark.Select(x => whatever);
, то каким-то образом компилятор должен знать, имеете ли вы в виду a.Select<Turtle, Result>
или a.Select<Giraffe, Result>
.Ни при каких обстоятельствах C # не будет пытаться угадать, что вы имели в виду a.Select<Animal, Result>
или a.Select<object, Result>
, потому что это не был один из предложенных вариантов .C # делает выбор только из доступных типов, а доступны следующие типы: IEnumerable<Turtle>
и IEnumerable<Giraffe>
.
Если нет оснований для принятия решения, вывод типа не выполняется.Так как мы получили доступ к методам расширения только после того, как все другие попытки разрешения перегрузки потерпели неудачу, мы, вероятно, потерпим неудачу при разрешении перегрузки на этом этапе.C # намек на то, что вы имели в виду.Самый простой способ это
ark.Select<Turtle, Result>(x => whatever);
Но вы также можете сделать
ark.Select((Turtle x) => whatever);
Или
((IEnumerable<Turtle>)ark).Select(x => whatever);
Или
(ark as IEnumerable<Turtle>).Select(x => whatever);
Это всехорошо.Вы пришли к выводу, что это компилируется:
ark.Cast<Turtle>().Select(x => whatever);
// NEVER DO THIS IN THIS SCENARIO
// USE ANY OF THE OTHER TECHNIQUES, NEVER THIS ONE
Вы понимаете, почему это опасно ?Не продолжайте, пока не поймете, почему это, вероятно, неправильно.Обоснуйте это.
В общем, опасно применять тип, который реализует два "одинаковых" универсальных интерфейса, потому что могут произойти очень странные вещи .Язык и среда выполнения не были предназначены для элегантной обработки такого рода объединения.Рассмотрим, например, как работает ковариация;что произойдет, если мы приведем ark
к IEnumerable<Animal>
?Посмотри, сможешь ли ты понять это;затем попробуйте и посмотрите, были ли вы правы.
К сожалению, вы находитесь в еще худшем положении;что если вы создадите экземпляр GenericCollection<TCollection, TItem>
, такой, что TItem
будет GeneralObject
? Теперь вы реализовали IEnumerable<GeneralObject>
дважды! Это действительно сбивает с толку пользователей, и CLR это совсем не нравится.
Лучше сделать так, чтобы Ark
не реализовывал ни интерфейс, носкорее, выставьте два метода, один из которых возвращает черепах, а второй - жирафов.Вы должны настоятельно рассмотреть возможность сделать то же самое в вашем классе.Лучшим дизайном было бы сделать GenericCollection<TCollection, TItem>
не реализующим IEnumerable<TItem>
, а иметь свойство IEnumerable<TItem> Items { get { ... } }
.
С этим дизайном вы можете затем сделать collection.Select
, чтобы получить общие объекты, или collection.Items.Select
, чтобы получить предметы, и проблема исчезнет.