【发布时间】:2015-04-23 15:15:56
【问题描述】:
假设我想要一个通用的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) 编译失败。
有没有办法解决这个问题,还是我真的把自己画到了角落里?
【问题讨论】:
-
你能把它设为
Box<U>并通过工厂方法传递实现特定的信息吗? -
@MillieSmith 删除 CRTP 当然可以,但这会导致无法控制像
Box<B, V> Merge<U, V>(Box<B, U> another, Func<T, U, V> merge)这样的方法实际上接受兼容的Boxes。