繁体   English   中英

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

[英]Returning `this` from generic parent class requires cast in child

我正在使用构建器模式 ,将重复的代码提取到“帮助器”类中,但是重复代码的一个方面我仍然不满意。

构建器模式允许链接实现代码,如下所示:

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

每个方法CarBuilderWheelsConvertible返回构建器类的相同实例( return this ), Build方法返回新实例化的Car

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

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));

在构建器类中,我尝试将返回类型从void更改为Builder

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

...但是编译器说返回类型必须是Builder<T> ie

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

好吧,公平,但在我的实现类中,我现在必须做一个演员:

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

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

我想我可能会遗漏一些基本的东西。 我可以避免重复演员表并且必须从每个构建器实现方法中“返回”吗?

不要把Chain放在基类中。 相反,将其作为通用扩展方法:

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

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

Builder<T>内部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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM