【问题标题】:Why does this result in CS0695?为什么这会导致 CS0695?
【发布时间】:2013-02-25 08:23:08
【问题描述】:
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,因此TInTOut 都不可能是object,对吧?那么为什么编译器会认为PipelineElement&lt;object, object&gt;PipelineElement&lt;TIn, TOut&gt; 可以变得相同呢?

编辑:是的,完全有可能多次实现同一个通用接口:

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

【问题讨论】:

  • 我删除了我的 cmets,我没有得到任何有用的东西。标记为收藏,我也想知道答案:)。为这个问题 +1!

标签: c# generics compiler-errors


【解决方案1】:

来自Compiler Error CS0695

“通用类型”不能同时实现“通用接口”和“通用” 接口”,因为它们可能会针对某些类型参数进行统一 替换。

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

您不能同时为抽象类实现 PipelineElementBase&lt;TIn, TOut&gt;PipelineElement&lt;object, object&gt; 接口。

正如错误页面所说,您应该这样做;

  • 仅实施其中一项或
  • 更改类型参数以避免冲突。

来自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。

  • 从 L 中删除所有重复项。

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

在上面的类声明X中,接口列表L包括 I&lt;U&gt;I&lt;V&gt;。声明无效,因为任何构造 类型与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() {…}
}

即使Derived&lt;U,V&gt; 实现了I&lt;U&gt; 这两个代码也是有效的 和I&lt;V&gt;。代码

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

调用Derived 中的方法,因为Derived&lt;int,int&gt; 有效 重新实现I&lt;int&gt;(§13.4.6)。

[SO 编辑强调。]

【讨论】:

  • 哪个冲突?有了这些类型约束,&lt;TIn, TOut&gt;&lt;object, object&gt; 就不会发生冲突。
  • @main-- “在确定所有可能的构造类型时,不考虑约束声明。”这是您问题的关键,但是恕我直言,这个答案以太多的细节掩盖了这个重要的句子。
猜你喜欢
  • 2014-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-27
  • 2017-04-26
  • 1970-01-01
  • 2012-05-04
  • 1970-01-01
相关资源
最近更新 更多