假设我有一个泛型类
public class G<T> {
}
我想将最终类声明为
public class F<T> where T : G<T> {
}
这似乎是可能的,但是如果我想使任务复杂化并向类 G 添加约束怎么办
public class A {
}
public class DA : A {
}
public class DB : A {
}
public class G<T> where T : A {
}
最后我想这样做
public class F<T> where T : G<T> {
}
这不起作用,它说 T 必须是 A 型,这是可以理解的,看起来我可以这样重写它
public class F<T, U> where T : G<U> where U : A {
}
但在这种情况下,用法有一个冗余声明
public class DF : F<G<DA>, DA> {
}
在使用 F 类时,我必须重复 DA 两次,即使很清楚如果我使用 G 作为泛型类型,G 的泛型类型是 DA。有没有办法避免这种冗余?
这样做
public class F<T> where T : G<T> { }
但这似乎没有多大意义。您希望F
参数化T
必须G<X>
X
再次T
的位置,即G<X>
,再次T
X
的位置等等......这是一个递归定义。
我认为您实际要定义的是这样的(所有示例都是无效的 C#)
public class F<T1<T2>> where T1 : G<T2> where T2 : A {
}
或者也许
public class F<T1> where T1 : G<T2> where T2 : A {
}
或者也许
public class F<G<T>> where T : A {
}
这些"泛型的泛型"称为高级类型,但不幸的是,C# 不支持它们。例如,Haskell和一些其他函数式语言也是如此。
有一个模拟 HKT 的 C# 库,它使用你找到的解决方法:指定内部类型两次。