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

如何在C#方法链中确保特定方法(如Throw())被调用?

问题

我想要在C#中创建一个使用方法链的API,确保在方法链末尾必须调用特定方法(例如Throw()),若未调用则抛出异常。

以下是我尝试实现的简化示例:

public interface IChainable
{
    IChainable Step1();
    IChainable Step2();
    void Throw();
}

public class Chainable : IChainable, IDisposable
{
    private bool _throwCalled = false;

    public IChainable Method1()
    {
        return this;
    }

    public IChainable Method2()
    {
        return this;
    }

    public void Throw()
    {
        _throwCalled = true;
    }

    public void Dispose()
    {
        if (!_throwCalled)
        {
            throw new InvalidOperationException("Throw() method must be called when finishing the chaining");
        }
    }
}

但我希望避免这种实现,因为它需要使用using块,而这在当前场景并不合适:

using (var chainable = new Chainable())
{
    chainable.Step1().Step2();
    // chainable.Throw(); // 若用户忘记调用Throw(),using块结束时会抛出异常
}

我正在寻找更健壮、确定的方法,确保Throw()在方法链末尾被调用且无需using块,是否有相关技术或模式可高效实现?


解决方案

分阶段接口模式(推荐)

核心是通过拆分接口划分方法链的构建阶段和终止阶段:构建阶段的接口只暴露链式操作方法,终止阶段的接口仅包含必须调用的Throw(),通过返回值类型切换强制用户完成终止步骤。

示例实现:

// 构建阶段:仅提供链式操作方法
public interface IChainBuilder
{
    IChainBuilder Step1();
    IChainBuilder Step2();
    // 最后一个构建方法返回终止接口,切换阶段
    IChainTerminator FinalizeBuild();
}

// 终止阶段:仅提供必须调用的结束方法
public interface IChainTerminator
{
    void Throw();
}

public class Chain : IChainBuilder, IChainTerminator
{
    public IChainBuilder Step1()
    {
        // 执行Step1业务逻辑
        return this;
    }

    public IChainBuilder Step2()
    {
        // 执行Step2业务逻辑
        return this;
    }

    public IChainTerminator FinalizeBuild()
    {
        // 完成构建前的收尾逻辑
        return this;
    }

    public void Throw()
    {
        // 执行最终逻辑并抛出异常
        throw new InvalidOperationException("触发预设业务异常");
    }
}

使用方式:

// 必须按 构建方法 → FinalizeBuild() → Throw() 的顺序调用,否则无法完成有效流程
new Chain().Step1().Step2().FinalizeBuild().Throw();

// 错误示例:只调用到FinalizeBuild(),后续没有Throw(),代码无实际执行结果(IChainTerminator无其他方法)
// new Chain().Step1().FinalizeBuild();

该方案优势:

  • 编译期引导约束:用户若遗漏Throw(),要么代码无意义,要么无法继续操作
  • 无需依赖IDisposable和using块,逻辑更直观
  • 接口职责单一,符合SOLID设计原则

单类型引导方案

如果不想拆分多个接口,可以设计一个单类型,让所有链式方法返回自身,仅Throw()为void方法,同时通过私有构造强制用户从静态入口创建实例,引导用户必须调用Throw()完成流程:

public class ChainHandler
{
    // 私有构造,强制通过静态方法创建实例
    private ChainHandler() { }

    public static ChainHandler Create() => new ChainHandler();

    public ChainHandler Step1()
    {
        // 执行Step1逻辑
        return this;
    }

    public ChainHandler Step2()
    {
        // 执行Step2逻辑
        return this;
    }

    public void Throw()
    {
        // 执行最终逻辑并抛出异常
        throw new InvalidOperationException("触发业务异常");
    }
}

使用方式:

ChainHandler.Create().Step1().Step2().Throw();

这种方案没有编译期强制,但通过API设计引导用户完成终止步骤——若不调用Throw(),整个链式调用没有任何实际终止逻辑,用户很容易发现遗漏。结合清晰的API注释,效果同样不错。

编译期强约束进阶方案

如果需要极致的编译期检查,可以利用C#泛型约束和状态标记类型,完全限制调用顺序:

// 状态标记接口,用于区分构建状态
public interface IUnbuilt { }
public interface IBuilt { }

public class Chain<TState> where TState : class
{
    private Chain() { }

    // 静态入口,初始状态为IUnbuilt
    public static Chain<IUnbuilt> Create() => new Chain<IUnbuilt>();

    // 仅当状态为IUnbuilt时,才能调用链式方法
    public Chain<IUnbuilt> Step1() where TState : IUnbuilt
    {
        // 执行Step1逻辑
        return this;
    }

    public Chain<IUnbuilt> Step2() where TState : IUnbuilt
    {
        // 执行Step2逻辑
        return this;
    }

    // 切换状态为IBuilt,仅允许IUnbuilt状态调用
    public Chain<IBuilt> CompleteBuild() where TState : IUnbuilt
    {
        return this as Chain<IBuilt>;
    }

    // 仅当状态为IBuilt时,才能调用Throw()
    public void Throw() where TState : IBuilt
    {
        throw new InvalidOperationException("触发预设异常");
    }
}

使用方式:

// 正确调用:严格遵循 初始化 → 构建 → 完成构建 → 抛出 的顺序
Chain.Create().Step1().Step2().CompleteBuild().Throw();

// 错误示例:未完成构建就调用Throw(),编译直接报错
// Chain.Create().Step1().Throw();

// 错误示例:完成构建后不调用Throw(),无法进行其他操作,代码无意义
// Chain.Create().Step1().CompleteBuild();

该方案完全在编译期约束了调用流程,确保Throw()必须被调用,缺点是实现相对繁琐,适合对API严谨性要求极高的场景。


内容的提问来源于stack exchange,提问作者Andrey Namikaze

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 07:13:14