skip to Main Content

I’m trying to create an API in C# that uses method chaining. I want to ensure that at the end of the chain, a specific method (e.g., Throw()) is called. If this method is not called, an exception should be thrown.

Here is a simplified example of what I’m trying to achieve:

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

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

    public IChainable Step1()
    {
        return this;
    }

    public IChainable Step2()
    {
        return this;
    }

    public void Throw()
    {
        _throwCalled = true;
    }

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

However, I want to avoid this because it requires opening a using block, which is not desired in this case:

using (var chainable = new Chainable())
{
    chainable.Step1().Step2();
    // chainable.Throw(); // If the user forgets to call Throw(), an exception is thrown when the using block ends
}

I’m looking for a more robust and deterministic way to ensure that Throw() is called at the end of the chain, without having to use a using block. Is there any technique or pattern that can help me implement this more efficiently?

Any help is appreciated!

2

Answers


  1. If I may suggest to the Finally block of Try-Catch-Finally block.
    Regardless of the code execution getting into try or catch, you will always triggers the "Finally" block.

    bool done = false;
    try
    {
       // some code here
       done = true;
    }
    catch(Exception e)
    {
       // some code here
       done = true;
    }
    finally
    {
      // check if done is true?
    }

    Hope this helps.

    Login or Signup to reply.
  2. If you don’t have side-effects in those methods Step1 and Step2, but you are doing some form of building the final object, you can introduce another interface IFinishedChainable that has methods relying on the state of the object after we call Throw or whatever end method we need to complete the chaining. And then change Throw return IFinishedChainable instead of void.

    Complete example:

    public interface IChainable {
        IChainable Step1();
        IChainable Step2();
        IFinishedChainable Throw();
    }
    
    public interface IFinishedChainable {
        void SomethingUseful();
    }
    
    public class Chainable : IChainable, IFinishedChainable {
        public IChainable Step1() {
            return this;
        }
    
        public IChainable Step2() {
            return this;
        }
    
        public IFinishedChainable Throw() {
            return this;
        }
    
        public void SomethingUseful() {
            Console.WriteLine("Hello World");
        }
    
    }
    

    Then usage is:

    IFinishedChainable finishedChainable = new Chainable()
    .Step1()
    .Step2()
    .Throw();// won't compile without it
    
    finishedChainable.SomethingUseful();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search