奇怪的重复模板模式与其他泛型类型

时间:2015-04-23 15:15:57

标签: c# generics crtp

我想说我想要一个可以包含内容的通用Box类,所以它是Box<T>Box<T>使用Transform方法返回Box<U>

public Box<U> Transform<U>(Func<T, U> transform)

到目前为止,这很简单。但是,我实际上需要一个抽象Box,因为值被装箱和转换的方式是特定于实现的。 (我不能有一个接口,因为有其他方法是通过抽象方法的组合实现的,但这并不会改变任何东西)。

当然,我希望我的重写Transform方法返回Box的适当子类,而不是Box本身。由于覆盖方法的返回类型在C#中是不变的,因此我转向curiously recurring template pattern(请参阅IComparable<T>):

public abstract class Box<B, T> where B : Box<B, T>

现在,我从Box<B, T>继承的每个班级都应该引用自己,或者所有地狱都松散了:

public class FooBox<T> : Box<FooBox, T>

然而,这完全破坏了Transform方法:

public abstract Box<B, U> Transform<U>(Func<T, U> transform);

无法使用The type 'B' cannot be used as type parameter 'B' in the generic type or method 'Test.Box<B,T>'. There is no implicit reference conversion from 'B' to 'Test.Box<B,U>'. (CS0311)进行编译。这是有道理的,因为返回类型现在是Box<B, U>而B是Box<B, T>,而不是Box<B, U>

直截了当的解决方案不起作用:

public abstract Box<B, U> Transform<U>(Func<T, U> transform) where B : Box<B, U>;

无法使用'Test.Box<B,T>.Transform<U>()' does not define type parameter 'B' (CS0699)进行编译。

有什么方法可以解决这个问题,还是我真的把自己画成了角落?

1 个答案:

答案 0 :(得分:1)

我认为直接修复的问题是重用B类型参数。尝试其他方法,并将其作为类型参数包含在内:

public abstract Box<B2, U> Transform<B2,U>(Func<T, U> transform) where B2 : Box<B2, U>;

更新:您说:

  

现在我不能保证B2和B实际上是相同的派生类,这是我的目标

但情况并非如此,B2不会(不能?)从B继承,如果您愿意,U可能会继承T。您可以将其包含在约束中。然而,对于模式来说,这并不是绝对必要的,因为它取决于Transform的主体来进行排序。

e.g:

public abstract Box<B2, U> Transform<B2,U>(Func<T, U> transform) 
    where B2 : Box<B2, U>
    where U : T