从通用父级 class 返回 `this` 需要在子级中强制转换

Returning `this` from generic parent class requires cast in child

我正在使用 builder pattern,已将重复代码提取到 'helper' class 但重复代码的一个方面我仍然不满意。

构建器模式允许像这样链接实现代码:

Car car = new CarBuilder().Wheels(4).Convertible().Build();

每个方法 CarBuilderWheelsConvertible return 构建器的相同实例 class (return this) 和Build 方法 return 新实例化 Car.

这是我对通用构建器的尝试 class:

public class Builder<T> where T : class 
{
    private Func<T, T> func;

    protected void SetInstantiator(Func<T, T> f) => this.func = f;

    protected void Chain(Action<T> action)
    {
        this.ChainFunc(action);
    }

    private ChainFunc(Action<T> action)
    {
        // SNIPPED
    }

    protected T Instantiate() => this.func(null);
}

这是我的通用构建器的实现:

public class CarBuilder : Builder<Car>
{
    public CarBuilder()
    {
        this.SetInstantiator(c => new Car());
        return this;
    }

    public CarBuilder Wheels(int wheels)
    {
        this.Chain(c => c.SetWheelCount(wheels));
        return this;
    }

    public CarBuilder Convertible()
    {
        this.Chain(c => c.RetractableRoof = true);
        return this;
    }

    public Car Build() => this.Instantiate();
}

困扰我的是每次调用 Chain 方法后重复的 return this,我想我可以将其推入 Chain 方法本身,即我想编写如下代码这个:

    public CarBuilder Wheels(int wheels) =>
        this.Chain(c => c.SetWheelCount(wheels));

在生成器 class 中,我尝试将 return 类型从 void 更改为 Builder:

protected Builder Chain(Action<T> action)
{
    this.ChainFunc(action);
    return this;
}

...但是编译器说 return 类型必须是 Builder<T>

protected Builder<T> Chain(Action<T> action)
{
    this.ChainFunc(action);
    return this;
}

好的,很公平,但在我的实现中class我现在必须做一个转换:

    public CarBuilder Wheels(int wheels) =>
        (CarBuilder)this.Chain(c => c.SetWheelCount(wheels));

所以我再次重复代码,所有方法现在都必须包含强制转换。将 class 类型从子类型传递到超类型感觉不对。

我想我可能遗漏了一些基本的东西。我可以避免重复转换和必须从每个构建器实现方法中 'return this' 吗?

不要将 Chain 放在基数 class 中。相反,将其设为通用扩展方法:

public static TBuilder Chain<TBuilder, TObject>(this TBuilder @this, Action<TObject> a)
 where TBuilder: Builder<TObject>
 => ...

将逻辑保留在受保护范围内的一种方法是添加调用的静态方法而不是实例方法。静态方法可以使用隐式转换为 return 调用者的类型

里面Builder<T>

protected void Chain(Action<T> action)
{
    //local chain logic
}

protected static BT Chain<BT>(BT builder, Action<T> action)
    where BT:Builder<T>
{
    builder.Chain(action);
    return builder;
}

内部调用 CarBuilder:

public CarBuilder Wheels(int wheels) => Chain(this , c => c.SetWheelCount(wheels));

public CarBuilder Convertible() => Chain(this, c => c.RetractableRoof = true);