为什么这会导致 CS0695? [英] Why does this result in CS0695?

查看:17
本文介绍了为什么这会导致 CS0695?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

public interface PipelineElement{IEnumerableRun(IEnumerable input, Action errorReporter);}公共接口阶段{}公共抽象类 PipelineElementBase: PipelineElement,PipelineElement<TIn, TOut>其中 TIn : 阶段 TOut : 阶段{IEnumerable<对象>PipelineElement.Run(IEnumerable input, Action errorReporter){return this.Run(input.Cast(), errorReporter).Cast();}公共抽象 IEnumerableRun(IEnumerable input, Action errorReporter);}

object 没有实现 Stage,因此 TInTOut 都不可能是 object,对吧?那么为什么编译器认为 PipelineElementPipelineElement 可以变得相同?

是的,完全有可能多次实现相同的通用接口:

公共接口 MyInterface{ }公共类 MyClass: MyInterface, MyInterface;{ }

来自 编译器错误 CS0695

<块引用>

'generic type' 不能同时实现 'generic interface' 和 'generic接口',因为它们可能会统一某些类型参数替换.

当一个泛型类实现多个时会出现这个错误相同通用接口的参数化,并且存在一个类型参数替换将使两个接口完全相同的.为了避免这个错误,只实现一个接口,或更改类型参数以避免冲突.

您不能同时为抽象类实现 PipelineElementBasePipelineElement 接口.

正如错误页面所说,你应该;

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

来自 C# 5.0 语言规范

<块引用>

13.4.2 实现接口的唯一性

泛型类型声明实现的接口必须保留对于所有可能的构造类型都是唯一的.如果没有这个规则,它将无法确定正确的调用方法构造类型.例如,假设一个泛型类声明被允许写成如下:

接口I{无效 F();}X U、V 类:I U 、I V 类{void I<U>.F() {...}void I<V>.F() {...}}

<块引用>

如果允许这样做,就不可能确定要使用哪个代码在以下情况下执行:

Ix = new X();x.F();

<块引用>

判断泛型类型声明的接口列表是否为有效,执行以下步骤:

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

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

  • 从 L 中删除任何重复项.

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

在上面的类声明X中,接口列表L由II.声明无效,因为任何构造UV 类型相同的类型会导致这两个接口类型相同.

在不同继承中指定的接口是可能的统一的层次:

接口I{无效 F();}类基:I{void I<U>.F() {…}}派生类:基,I//行{void I<V>.F() {…}}

即使 Derived 实现了 I,此代码也是有效的和 I.代码

Ix = new Derived();x.F();

调用Derived中的方法,因为Derived有效重新实现 I(第 13.4.6 节).

[SO 编辑强调.]

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 doesn't implement Stage, therefore neither TIn nor TOut could ever be object, right? So why does the compiler think that PipelineElement<object, object> and PipelineElement<TIn, TOut> can become identical?

EDIT: Yes, it is perfectly possible to implement the same generic interface multiple times:

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

解决方案

From Compiler Error CS0695

'generic type' cannot implement both 'generic interface' and 'generic interface' because they may unify for some type parameter substitutions.

This error occurs when a generic class implements more than one parameterization of the same generic interface, and there exists a type parameter substitution which would make the two interfaces identical. To avoid this error, implement only one of the interfaces, or change the type parameters to avoid the conflict.

You can't implement both PipelineElementBase<TIn, TOut> and PipelineElement<object, object> interfaces to your abstract class.

As the error page said, you should;

  • Implement only one of these or
  • Change the type parameters to avoid the conflict.

From C# 5.0 Language Specification

13.4.2 Uniqueness of implemented interfaces

The interfaces implemented by a generic type declaration must remain unique for all possible constructed types. Without this rule, it would be impossible to determine the correct method to call for certain constructed types. For example, suppose a generic class declaration were permitted to be written as follows:

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

Were this permitted, it would be impossible to determine which code to execute in the following case:

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

To determine if the interface list of a generic type declaration is valid, the following steps are performed:

  • Let L be the list of interfaces directly specified in a generic class, struct, or interface declaration C.

  • Add to L any base interfaces of the interfaces already in L.

  • Remove any duplicates from L.

  • If any possible constructed type created from C would, after type arguments are substituted into L, cause two interfaces in L to be identical, then the declaration of C is invalid. Constraint declarations are not considered when determining all possible constructed types.

In the class declaration X above, the interface list L consists of I<U> and I<V>. The declaration is invalid because any constructed type with U and V being the same type would cause these two interfaces to be identical types.

It is possible for interfaces specified at different inheritance levels to unify:

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() {…}
}

This code is valid even though Derived<U,V> implements both I<U> and I<V>. The code

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

invokes the method in Derived, since Derived<int,int> effectively re-implements I<int>(§13.4.6).

[Emphasis by the SO editor.]

这篇关于为什么这会导致 CS0695?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆