为什么会导致CS0695?

mai*_*n-- 10 c# generics compiler-errors

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);
}
Run Code Online (Sandbox Code Playgroud)

object没有实施Stage,因此既不是TInTOut不可能object,对吧?那么为什么编译器会认为PipelineElement<object, object>并且PipelineElement<TIn, TOut>可以变得相同呢?

编辑:是的,完全可以多次实现相同的通用接口:

public interface MyInterface<A> { }
public class MyClass: MyInterface<string>, MyInterface<int> { }
Run Code Online (Sandbox Code Playgroud)

Son*_*nül 10

Compiler Error CS0695

"泛型类型"不能同时实现"通用接口"和"通用接口",因为它们可能统一某些类型参数替换.

当泛型类实现相同通用接口的多个参数化时会发生此错误,并且存在类型参数替换,这将使两个接口相同.要避免此错误,请仅实现其中一个接口,或更改类型参数以避免冲突.

您不能同时实现抽象类的接口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() {...}
}
Run Code Online (Sandbox Code Playgroud)

如果允许这样做,则在以下情况下无法确定要执行的代码:

I<int> x = new X<int,int>();
x.F();
Run Code Online (Sandbox Code Playgroud)

要确定泛型类型声明的接口列表是否有效,请执行以下步骤:

  • 设L是在泛型类,结构或接口声明C中直接指定的接口列表.

  • 添加到L中已有的接口的任何基接口.

  • 从L.删除任何重复.

  • 如果从C创建的任何可能的构造类型将类型参数替换为L后,导致L中的两个接口相同,则C的声明无效.在确定所有可能的构造类型时,不考虑约束声明.

X上面的类声明中,接口列表L由I<U>和组成 I<V>.声明无效,因为任何具有UV相同类型的构造类型都会导致这两个接口是相同的类型.

在不同的继承级别指定的接口可以统一:

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() {…}
}
Run Code Online (Sandbox Code Playgroud)

此代码是有效的,即使Derived<U,V>同时实现了I<U>I<V>.代码

I<int> x = new Derived<int,int>();
x.F();
Run Code Online (Sandbox Code Playgroud)

调用方法Derived,因为Derived<int,int>有效地重新实现I<int>(§13.4.6).

[SO编辑强调.]

  • @ main--"在确定所有可能的构造类型时,不考虑约束声明." 这是你的问题的关键,但这个答案掩盖了这个重要的句子太多细节恕我直言. (5认同)