5

我一直在尝试将一些使用(有界)通配符泛型的 Java 代码转换为 C#。我的问题是,Java 似乎允许泛型类型在与通配符一起使用时既是协变的又是逆变的。例如:

爪哇:

interface IInterf { }

class Impl implements IInterf { }

interface IGeneric1<T extends Impl> {
    void method1(IGeneric2<?> val);
    void method1WithParam(T val);
}

interface IGeneric2<T extends Impl> {
    void method2(IGeneric1<?> val);
}

abstract class Generic<T extends Impl> implements IGeneric1<T>, IGeneric2<T> {
    public void method1(IGeneric2<?> val2) {
        val2.method2(this);
    }
}

...作品。

C# 等价物 (?)

interface IInterf { }

class Impl : IInterf { }

interface IGeneric1<T> where T:Impl {
  //Java was: 
  //void method1(IGeneric2<?> val2);
    void method1(IGeneric2<Impl> val);
    void method1WithParam(T to);
}

interface IGeneric2<T>where T:Impl {
    void method2(IGeneric1<Impl> val);
}

abstract class Generic<T> : IGeneric1<T>, IGeneric2<T> where T : Impl
{
  //Java was: 
  //public void method1(IGeneric2<?> val2) {
    public void method1(IGeneric2<Impl> val2)
    {
         val2.method2(this); //'this': Argument type 'Generic<T>' is not 
                             //assignable to parameter type 'IGeneric1<Impl>'
    }

    public abstract void method1WithParam(T to);
    public abstract void method2(IGeneric1<Impl> val);
}

...编译失败 - 请参阅评论中的错误。这是意料之中的,因为 IGeneric 的泛型参数没有为协方差标记为“out”。

如果我改变这个:

interface IGeneric1<T> where T:Impl {

对此

interface IGeneric1<out T> where T:Impl 

错误消失了,但出现了另一个错误,用于在同一接口内声明采用泛型参数的方法:

interface IGeneric1<T> where T:Impl {
    void method1WithParam(T val);  //Parameter must be input-safe. 
                      //Invalid variance: The type parameter 'T' must be
                      //contravariantly valid on 'IGeneric1<out T>'.

建议?

[另请参阅后续问题以了解更难的情况]

4

1 回答 1

7

您需要将 Java 通配符泛型方法转换为本身就是泛型的 C# 方法。例如,这个:

interface IGeneric2<T extends Impl> {
    void method2(IGeneric1<?> val);
}

应该翻译成

interface IGeneric2<T>where T:Impl {
    void method2<U>(IGeneric1<U> val) where U:Impl;
}

有必要重复T指定IGeneric1<T>的类型约束作为 的类型约束U

这样做的原因是,在 Java 版本中,对于 and 的形参的类型实参有隐约束:如果形参必须是某种类型,那么显然必须是 an ,否则它不可能为该类型实现。method1method2IGeneric1<X>XImplIGeneric1

在 C# 中,约束必须是显式的,因此您重复 whatIGeneric1<T>IGeneric2<T>require T

所以等效的代码是:

interface IInterf { }

class Impl : IInterf { }

interface IGeneric1<T> where T:Impl {
    void method1<U>(IGeneric2<U> val) where U:Impl;
    void method1WithParam(T to);
}

interface IGeneric2<T>where T:Impl {
    void method2<U>(IGeneric1<U> val) where U:Impl;
}

abstract class Generic<T> : IGeneric1<T>, IGeneric2<T> where T : Impl
{
    public void method1<U>(IGeneric2<U> val2) where U:Impl
    {
        val2.method2(this);
    }

    public abstract void method1WithParam(T to);
    public abstract void method2<U>(IGeneric1<U> val) where U:Impl;
}
于 2013-01-11T11:57:38.450 回答