Почему это приводит к CS0695?

public interface PipelineElement<in TIn, out TOut>
{
    IEnumerable<TOut> Run(IEnumerable<TIn> input, Action<Error> errorReporter);
}

public interface Stage
{
}

public abstract class PipelineElementBase<TIn, TOut> : PipelineElement<object, object>,
    PipelineElement<TIn, TOut> where TIn : Stage where TOut : Stage
{
    IEnumerable<object> PipelineElement<object, object>.Run(IEnumerable<object> input, Action<Error> errorReporter)
    {
        return this.Run(input.Cast<TIn>(), errorReporter).Cast<object>();
    }

    public abstract IEnumerable<TOut> Run(IEnumerable<TIn> input, Action<Error> errorReporter);
}

object не выполнять Stage, таким образом, ни TIn, ни TOut может быть object, да? Так почему же компилятор думает, что PipelineElement<object, object> и PipelineElement<TIn, TOut> может стать идентичными?

EDIT: да, вполне возможно реализовать один и тот же общий интерфейс несколько раз:

public interface MyInterface<A> { }
public class MyClass: MyInterface<string>, MyInterface<int> { }

1 ответов


С Compiler Error CS0695

'generic type' не может реализовать как "generic interface", так и " generic interface', потому что они могут объединяться для некоторого параметра типа замены.

эта ошибка возникает, когда универсальный класс реализует более одного параметризация одного и того же универсального интерфейса, и существует подстановка параметров типа, которая сделает два интерфейса идентичный. Чтобы избежать этой ошибки, реализуйте только один из взаимодействие, или измените параметры типа, чтобы избежать конфликта.

вы не можете реализовать как PipelineElementBase<TIn, TOut> и PipelineElement<object, object> интерфейсы к вашему абстрактному классу.

как сказано на странице ошибок, вы должны;

  • реализовать только один из них или
  • измените параметры типа, чтобы избежать конфликта.

С C# 5.0 Language Specification

13.4.2 уникальность реализованного интерфейсы

интерфейсы, реализованные объявлением универсального типа, должны оставаться уникальная для всех возможных видов. Без этого правила невозможно определить правильный метод для вызова определенного сконструированный тип. Например, предположим объявление универсального класса разрешалось писать следующим образом:

interface I<T>
{
    void F();
}
class X<U,V>: I<U>, I<V>
{
    void I<U>.F() {...}
    void I<V>.F() {...}
}

если бы это было разрешено, было бы невозможно определить, какой код выполнить в следующий случай:

I<int> x = new X<int,int>();
x.F();

чтобы определить, является ли список интерфейса объявления универсального типа допустимо, выполняются следующие действия:

  • пусть L-список интерфейсов, непосредственно указанных в общем классе, структуре или объявлении интерфейса C.

  • добавьте в L любые базовые интерфейсы интерфейсов уже в L.

  • удалить все дубликаты из Л.

  • если любой возможный построенный тип, созданный из C, после того, как аргументы типа будут заменены на L, вызовет два интерфейса в L идентично, тогда объявление C недействительно. ограничение заявления не учитываются при определении всех возможных сконструированный тип.

в объявлении класса X выше, список интерфейса L состоит из I<U> и I<V>. Декларация недопустимый, потому что любой построенный введите с U и V будучи того же типа вызовет эти два интерфейсы должны быть идентичными типами.

это возможно для интерфейсов, указанных при различном наследовании уровни для объединения:

interface I<T>
{
  void F();
}
class Base<U>: I<U>
{
  void I<U>.F() {…}
}
class Derived<U,V>: Base<U>, I<V> // Ok
{
  void I<V>.F() {…}
}

этот код действителен, хотя Derived<U,V> реализует как I<U> и I<V>. Код

I<int> x = new Derived<int,int>();
x.F();

вызывает метод Derived С Derived<int,int> эффективно re-implements I<int>(§13.4.6).

[выделено редактором SO.]