我可以让这个C#代码做我想要的并让ShapeBuilder.color返回这个派生的子类型吗?
class Shape {
public String Color { get; private set; }
public Shape(String color) {
this.Color = color;
}
}
class Circle : Shape {
public int Radius { get; private set; }
public Circle(String color, int radius) : base(color) {
this.Radius = radius;
}
public override String ToString() {
return String.Format("Circle c={0} r={1}", this.Color, this.Radius);
}
}
class ShapeBuilder {
// How can this function return the subtype, not just a ShapeBuilder?
public ShapeBuilder color(String color) {
this._color = color;
return this;
}
protected String _color;
}
class CircleBuilder : ShapeBuilder {
public CircleBuilder radius(int radius) {
this._radius = radius;
return this;
}
public Circle build() {
return new Circle(_color, _radius);
}
protected int _radius;
}
class Program {
static void Main() {
// This works.
Circle c1 = new CircleBuilder().radius(5).build();
Console.WriteLine("c1: " + c1);
// This won't compile, because color returns ShapeBuilder rather than CircleBuilder.
Circle c2 = new CircleBuilder().color("blue").build();
Console.WriteLine("c2: " + c2);
}
}
在Scala中,我会这样做:
case class Shape(val color: String)
class Circle(color: String, radius: Int) extends Shape(color)
class ShapeBuilder {
def color(color: String): this.type = {
this.color = color
this
}
def build() = new Shape(color)
protected var color: String = ""
}
class CircleBuilder extends ShapeBuilder {
def radius(radius: Int): this.type = {
this.radius = radius
this
}
override def build() = new Circle(color, radius)
protected var radius: Int = 0
}
object BuilderTest extends App {
val c = new CircleBuilder().color("blue").radius(5).build();
}
答案 0 :(得分:2)
public class Shape {
public String Color { get; private set; }
public Shape(String color) {
this.Color = color;
}
}
public class Circle : Shape {
public int Radius { get; private set; }
public Circle(String color, int radius)
: base(color) {
this.Radius = radius;
}
public override String ToString() {
return String.Format("Circle c={0} r={1}", this.Color, this.Radius);
}
}
public class ShapeBuilder<TBuilder, TShape>
where TBuilder : ShapeBuilder<TBuilder, TShape>
where TShape : Shape {
// How can this function return the subtype, not just a ShapeBuilder?
public TBuilder color(String color) {
this._color = color;
return (TBuilder)this;
}
public virtual TShape build() {
return default(TShape);
}
protected String _color;
}
public class CircleBuilder : ShapeBuilder<CircleBuilder, Circle> {
public CircleBuilder radius(int radius) {
this._radius = radius;
return this;
}
public override Circle build() {
return new Circle(_color, _radius);
}
protected int _radius;
}
答案 1 :(得分:2)
可以使用泛型来完成。 Scala版本是最好的,因为它根本不需要泛型来提供this
的派生类型this.type
。这是C#版本:
class Shape {
public String Color { get; private set; }
public Shape(String color) {
this.Color = color;
}
public override String ToString() {
return String.Format("Shape c={0}", this.Color);
}
}
class Circle : Shape {
public int Radius { get; private set; }
public Circle(String color, int radius) : base(color) {
this.Radius = radius;
}
public override String ToString() {
return String.Format("Circle c={0} r={1}", this.Color, this.Radius);
}
}
interface Builder<T> {
T build();
}
abstract class AbstractShapeBuilder<B, T> : Builder<T> where B : AbstractShapeBuilder<B, T> where T : Shape {
abstract protected B getThis();
abstract public T build();
public B color(String color) {
this._color = color;
return getThis();
}
protected String _color;
}
class ShapeBuilder : AbstractShapeBuilder<ShapeBuilder, Shape> {
override protected ShapeBuilder getThis() { return this; }
override public Shape build() {
return new Shape(_color);
}
}
abstract class AbstractCircleBuilder<B, T> : AbstractShapeBuilder<B, T> where B : AbstractCircleBuilder<B, T> where T : Circle {
public B radius(int radius) {
this._radius = radius;
return getThis();
}
protected int _radius;
}
class CircleBuilder : AbstractCircleBuilder<CircleBuilder, Circle> {
override protected CircleBuilder getThis() { return this; }
override public Circle build() {
return new Circle(_color, _radius);
}
}
class Program {
static void Main() {
Console.WriteLine("CircleBuilder: v1");
Shape s1 = new ShapeBuilder().color("yellow").build();
Console.WriteLine("s1: " + s1);
Circle c1 = new CircleBuilder().color("blue").radius(3).build();
Console.WriteLine("c1: " + c1);
}
}
仅供参考,这是Java版本:
public class BuilderTest {
public static class Shape {
public Shape(String color) {
this.color = color;
}
@Override public String toString() {
return String.format("shape. color=%s.", color);
}
public final String color;
}
public static class Circle extends Shape {
public Circle(String color, int radius) {
super(color);
this.radius = radius;
}
@Override public String toString() {
return String.format("circle. color=%s. radius=%d.", color, radius);
}
public final int radius;
}
@FunctionalInterface
public static interface Builder<T> {
public T build();
}
public static abstract class AbstractShapeBuilder<B extends AbstractShapeBuilder<B>> {
protected abstract B getDerivedThis();
public B color(String color) {
this.color = color;
return getDerivedThis();
}
String color;
}
public static class ShapeBuilder extends AbstractShapeBuilder<ShapeBuilder> implements Builder<Shape> {
@Override protected ShapeBuilder getDerivedThis() { return this; }
@Override public Shape build() {
return new Shape(color);
}
}
public static abstract class AbstractCircleBuilder<B extends AbstractCircleBuilder<B>> extends AbstractShapeBuilder<B> {
public B radius(int radius) {
this.radius = radius;
return getDerivedThis();
}
int radius;
}
public static class CircleBuilder extends AbstractCircleBuilder<CircleBuilder> implements Builder<Circle> {
@Override protected CircleBuilder getDerivedThis() { return this; }
@Override public Circle build() { return new Circle(color, radius); }
}
public static void main(String[] args) throws Exception {
Shape s = new ShapeBuilder().color("red").build();
System.out.println("s = " + s);
Circle c = new CircleBuilder().color("blue").radius(5).build();
System.out.println("c = " + c);
}
}
答案 2 :(得分:2)
最简单,最惯用的方法是使用new
方法。
class ShapeBuilder {
// How can this function return the subtype, not just a ShapeBuilder?
public ShapeBuilder color(String color) {
this._color = color;
return this;
}
protected String _color;
}
class CircleBuilder : ShapeBuilder {
public new CircleBuilder color(String color) {
return (CircleBuilder)base.color(color)
}
}
为什么这是一个很好的方法呢?
泛型在这种情况下很糟糕,因为它们使编写在不同ShapeBuilders上以多态方式运行的代码变得更加复杂。像这样的通用基类往往会强制调用代码也是通用的,没有主要的好处。
ShapeBuilder s = new CircleBuilder(); s.color(Red);
比AbstractShapeBuilder<Circle, CircleBuilder> s = new CircleBuilder(); s.color(Red);
使用这样的new
关键字允许子类型的用户获得了解特定类型的好处,并且还允许超类型的用户以多态方式运行,而无需引入任何呼叫者的额外复杂性。这种技术在整个地方的.NET Framework中使用,你甚至不会注意到它,因为它非常直观 - SqlConnection.CreateCommand()和OleDbConnection.CreateCommand()的实现方式即使它们具有不同的返回类型,也使用相同的基本方法。
Maybe Jon Skeet doesn't like using new
,但我觉得通用版本更加丑陋,可读性更低,使用起来也更复杂。
答案 3 :(得分:0)
请参阅:How to return subtype in overridden method of subclass in C#?
也许你可以使用泛型?
ShapeBuilder<T>
请参阅Stormenet的示例。
不使用泛型,你运气不好,所以你的回答基本上是“不”。
那么你只是在寻找可能的替代方案:
另一种选择(除了模板)是使用对象初始化器:
http://msdn.microsoft.com/en-us/library/bb397680.aspx
这也不是你想要的,但你不能总是得到你想要的东西:)
StudentName student2 = new StudentName
{
FirstName = "Craig",
LastName = "Playstead",
};