You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Builder模式时,非泛型方法如何返回自身精确类型实例(无需强制转换)

解决Builder模式中基类虚方法链式调用返回派生类的问题

问题场景

在使用Builder模式开发构建器时,基类包含一个虚方法SomeMethod,通过返回自身实例支持链式调用(如builder.SomeMethod().OtherMethod())。但问题在于,派生类拥有独有的方法(比如Derived1的OtherMethod、Derived2的AnotherOneMethod),而SomeMethod默认返回基类Base类型,导致无法直接链式调用派生类的方法,编译报错CS1061。

基础代码示例

public abstract class Base
{
    public virtual Base SomeMethod()
    {
        return this;
    }
}

public class Derived1 : Base
{
    public void OtherMethod()
    {
        // 业务逻辑
    }
}

public class Derived2 : Base
{
    public void AnotherOneMethod()
    {
        // 业务逻辑
    }
}

期望调用方式(编译报错)

var d1 = new Derived1();
d1.SomeMethod().OtherMethod(); // CS1061 'Base' does not contain a definition for 'OtherMethod'

var d2 = new Derived2();
d2.SomeMethod().AnotherOneMethod(); // CS1061 'Base' does not contain a definition for 'AnotherOneMethod'

已尝试但不满意的方案

  • 强制转换:((Derived1)d1.SomeMethod()).OtherMethod(),链式调用较长时代码繁琐且可读性差
  • 泛型方法:d1.SomeMethod<Derived1>().OtherMethod(),调用时重复指定类型冗余
  • 拆分链式调用:d1 = new Derived1(); d1.SomeMethod(); d1.OtherMethod();,违背Builder模式链式调用的设计初衷
  • 协变与逆变接口:尝试后未实现预期效果

泛型基类方案的局限

曾尝试泛型基类方案,单层继承时可行:

public abstract class Base<T> where T : Base<T>
{
    public virtual T SomeMethod()
    {
        return this as T;
    }
}

public class Derived1 : Base<Derived1>
{
    public void OtherMethod()
    {
        // 业务逻辑
    }
}

// 调用正常
var d1 = new Derived1();
d1.SomeMethod().OtherMethod();

但该方案在多层继承时失效,比如定义Derived2 : Derived1,此时SomeMethod返回的是Derived1类型,无法直接调用Derived2的独有方法。

可行解决方案:多层继承下的类型适配

要解决多层继承的问题,核心是让每个派生类重写SomeMethod时返回自身类型,确保链式调用的类型正确性。

方案1:重写虚方法指定返回类型

public abstract class Base<T> where T : Base<T>
{
    public virtual T SomeMethod()
    {
        return this as T;
    }
}

public class Derived1 : Base<Derived1>
{
    public void OtherMethod() { }
}

public class Derived2 : Derived1
{
    public void AnotherMethod() { }

    // 重写基类方法,返回Derived2类型
    public override Derived2 SomeMethod()
    {
        return this;
    }
}

// 调用正常
var d2 = new Derived2();
d2.SomeMethod().AnotherMethod();

方案2:结合协变接口增强灵活性

通过协变接口定义方法契约,配合泛型基类实现类型兼容:

public interface IBuilder<out T> where T : IBuilder<T>
{
    T SomeMethod();
}

public abstract class BaseBuilder<T> : IBuilder<T> where T : BaseBuilder<T>
{
    public virtual T SomeMethod()
    {
        return this as T;
    }
}

public class Derived1Builder : BaseBuilder<Derived1Builder>
{
    public void OtherMethod() { }
}

public class Derived2Builder : Derived1Builder
{
    public void AnotherMethod() { }

    public override Derived2Builder SomeMethod()
    {
        return this;
    }
}

// 调用正常
var d2 = new Derived2Builder();
d2.SomeMethod().AnotherMethod();

这两种方案都能保证单层或多层继承下,链式调用时方法返回正确的派生类类型,无需额外转换,符合Builder模式的设计思想。

内容的提问来源于stack exchange,提问作者Sergey Khachaturov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 09:05:37