Chaining methods with callback parameters

giggioz

New member
Joined
Oct 10, 2021
Messages
2
Programming Experience
3-5
Hi,

how do you create a class that can be chained with some methods (OnStart, OnComplete, OnUpdate, etc...) that accept callbacks as parameters and trigger them later on?

instanceOfClass.OnStart(myStartFunction).OnComplete(myCompleteFunction);

Thanks!
 
Seems like an abuse of the fluent API style of programming, as well as goes against the .NET Framework naming convention. Normally you would declare public events for the class which is the C# accepted way of doing things. Those look something like:
C#:
class StartEventArgs : EventArgs
{
    public int MyProperty { get; set; }
}

class MyJob
{
    public event EventHandler<StartEventArgs> Start;
    public event EventHandler Complete;

    protected virtual void OnStart(StartEventArgs e)
        => Start?.Invoke(this, e);

    protected virtual void OnComplete(EventArgs e)
        => Complete?.Invoke(this, e);

    public void Execute()
    {
        OnStart(new StartEventArgs() { MyProperty = 2 });
        // do work here
        OnComplete(new EventArgs());
    }
}

:

var job = new MyJob();
job.Start += (o, e) => Console.WriteLine($"Started {e.MyProperty}");
job.Complete += (o, e) => Console.WriteLine("Completed");

Notice how the internal protected methods are named OnEventName. The event handlers are invoked within those methods. Parameters are passed via the EventArgs derived classes.
 
But if you want to join the VB6, Java, C, and the C++ programmers who are trying to kill the old C#/.NET Framework's guiding principle of "least surprise" by breaking conventions, one way to go about implementing what you want would look something like:
Bad C# code:
class StartEventArgs : EventArgs
{
    public int MyProperty { get; set; }
}

class MyJob
{
    Action<int> _onStart;
    Action _onComplete;

    public MyJob OnStart(Action<int> onStart)
    {
        _onStart = onStart;      
        return this;      
    }

    public MyJob OnComplete(Action onCompete)
    {
        _onComplete = onComplete;
        return this;
    }

    public void Execute()
    {
        if (_onStart != null)
            _onStart(2);
        // do work here
        if (_onComplete)
            _onComplete();
    }
}

:

var job = new MyJob()
    .OnStart(myProperty => Console.WriteLine($"Started {myProperty}"))
    .OnComplete(() => Console.WriteLine("Completed"));
 
Last edited:
But if you want to join the VB6, Java, C, and the C++ programmers who are trying to kill the old C#/.NET Framework's guiding principle of "least surprise" by breaking conventions, one way to go about implementing what you want would ...
:)
I won't kill anyone, I just saw this compact (and expressive in my opinion) form and I was just curious how it was done.
Thanks for sharing your approaches!
 
There are places where the fluent API style works very well within C#. Example the chaining of LINQ extension methods, or the chaining of configuration for ASP.NET Core. The Moq folks did a very good job of straddling the configuration you are trying to do above for setting up mocks but without colliding into the OnEventName() naming convention.
 
I won't kill anyone,
That's what they said when people first started misusing the word "decimate" and look where we are now. It used to mean kill 1 out of 10. Now it means kill the majority. They said the same about people misusing "begs the question" to mean "raising the question" instead of the original meaning of using circular reasoning in a debate. Death by a thousand cuts. Next thing you know, C# programmers will be using Java and JavaScript style One Bracing Style instead of the recommended Allman style.
 
Back
Top Bottom