具有泛型 class 的泛型函​​数:无隐式引用转换

Generic function with generic class: no implicit reference conversion

我正在尝试通过引入通用函数来清理一些重复的代码块。但我没能做到,我感觉我的 class 继承结构变得比我试图清理的代码更混乱...

这里是对所涉及的 classes 的抽象概述:

接口:

interface Ia
interface Ib : Ia
interface Ic : Ib

class是:

class Ca<T> where T : Ia
class Cb<T> : Ca<T> where T : Ia
class Cc : Cb<Ic>

函数:

void F<T>(T t) where T : Ca<Ib>

无效的函数调用:

F<Cc>(my_c);

错误:

The type 'Cc' cannot be used as type parameter 'T' in the generic type or method 'F<T>(T)'. There is no implicit reference conversion from 'Cc' to 'Ca<Ib>'.

我猜到错误中的 'implicit' 这个词是指 class 定义中没有 where T : Ib。所以我又加了一个class

class Cb2<T> : Cb<T> where T : Ib

并使 Cc 继承自 Cb2 而不是 Cb。但这导致了同样的错误。

谁能解释为什么这是受限的,我该如何解决?

谢谢!

通常 C# 不允许泛型参数替换,即使它们是继承的 类。这在添加 variance 修饰符后发生了变化。

您需要的是协变性,它允许使用派生类型代替泛型参数。但是方差修饰符仅适用于接口和委托,因此 CaCbCc 应该是允许这样做的接口。最接近它的是:

interface Ia {}
interface Ib : Ia {}
interface Ic : Ib {}

interface Ca<out T> where T : Ia {}
interface Cb<out T> : Ca<T> where T : Ia {}
interface Cc : Cb<Ic> {}

class Main
{
    void F<T>(T t) where T : Ca<Ib>
    {}

    void M()
    {
      F<Cc>(null);
    }
}

请注意 CaCb 定义中的 out T

More about out modifier

要使此代码有效,您需要使用一个接口来启用协变,如 Pavel 之前所说。你只需要一个最高级别的。

interface ICa<out T> where T : Ia
class Ca<T> : ICa<T> where T : Ia
class Cb<T> : Ca<T> where T : Ia
class Cc : Cb<Ic>

方法签名应该是这样的

void F<T>(T t) where T : ICa<Ib>