当前位置: 首页 > 面试题库 >

.NET是否等效于具有协方差和反方差的Java通配符?

段干恺
2023-03-14
问题内容

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

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>'.

有什么建议吗?

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


问题答案:

您需要将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,因为否则它将无法实现该类型。method1``method2``IGeneric1<X>``X``Impl``IGeneric1

在C#中的约束必须是明确的,所以你复述IGeneric1<T>IGeneric2<T>要求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;
}


 类似资料:
  • 问题内容: 我一直试图将一些使用(有界)通配符泛型的Java代码转换为C#。我的问题是,Java与通配符一起使用时似乎允许泛型既协变又协变。 [这是从先前的问题中衍生出来的,该问题处理的是更简单的有界通配符案例] Java-作品: C# -无法编译… 如果我更改interface IGeneric1 为interface IGeneric1 上述错误,错误会消失,但会method1WithPara

  • 问题内容: 请显示一个有关Java中协方差和逆方差的好例子。 问题答案: 协方差: Sub#getSomething是协变的,因为它返回Super#getSomething的返回类型的子类(但完全填充了Super.getSomething()的协定) 逆差 Sub#doSomething是互变的,因为它采用了Super#doSomething的参数的超类的参数(但是,再次填充了Super#doSo

  • 问题内容: 谁能解释我,编程语言理论中协变和逆变的概念吗? 问题答案: 协方差 非常简单,最好从某些收集类的角度来考虑。我们可以 参数化 的一些类型参数类。也就是说,我们的列表包含some 类型的元素。如果,列表将是协变的 S是Tiff列表的子类型List [S]是List [T]的子类型 (在这里,我使用数学定义 iff 表示 当且仅当 。) 也就是说,a 是一个 。如果有一些例程接受a 作为参

  • 我正在阅读为什么Java中的数组协方差不好(为什么数组是协方差的,而泛型是不变的?)。如果是的子类型,则是的子类型。这是一个问题,因为这样的事情是可以做的: 这与“正确”实现的泛型不同。不是的子类型 我试图理解为什么它是坏的本质,并且刚刚读了关于LSP的文章。它有没有违反LSP?似乎没有明显的违规行为。

  • 问题内容: 协方差(大致)是在使用它们的复杂类型中 镜像 “简单”类型的 继承 的能力。 例如,我们始终可以将的实例视为的实例。如果ComplexType是协变的,则可以将A 视为a 。 我想知道:协方差的“类型”是什么,它们与C#有什么关系(是否支持它们?) 代码示例将很有帮助。 例如,一种类型是Java支持的 返回类型covariance ,但C#不支持。 我希望有功能编程知识的人也能加入!

  • 本文向大家介绍什么是偏差和方差?相关面试题,主要包含被问及什么是偏差和方差?时的应答技巧和注意事项,需要的朋友参考一下 泛化误差可以分解为偏差的平方加上方差加上噪声。 偏差度量了学习算法的期望预测和真实结果的偏离程度,刻画了学习算法本身的拟合能力 方差度量了同样大小的训练集的变动所导致的学习性能的变化,刻画了数据扰动所造成的影响 噪声表达了当前任务上任何学习算法所能达到的期望泛化误差下界,刻画了问