1

I have async/awaited methods in my Connected anonymous method implementation and I wonder which one of these is the best to use in my case. I put examples below and added information according to what I know. Are my statements correct? Anything else important that I'm missing?

EventHandler

The only disadvantage to me is that the anonymous method is basically async void. Yes, we can have async calls, but they will be kinda "fire and forget/crash".

public class Test
{
    public event EventHandler<ConnectEventArgs>? Connected;

    public ValueTask StartAsync()
    {
        Connected?.Invoke(this, new ConnectEventArgs(...))
    }
}

var test = new Test();

test.Connected += async (sender, e) => // private async void OnConnect(object? sender, ConnectEventArgs e) => BAD
{
    await SendAsync(); // fire and forget
};

await test.StartAsync();

Func

What I notice is that we can have async calls without having to worry about async void. I think that's the only good way to have async/awaited method calls. Isn't it?

public class Test
{
    public event Func<Task>? Connected;

    public ValueTask StartAsync()
    {
        await (Connected?.Invoke() ?? Task.CompletedTask).ConfigureAwait(false);
    }
}

var test = new Test();

test.Connected += async () => // private async Task OnConnect()
{
    await SendAsync(); // Should be okay?
};

await test.StartAsync();

Action

The only difference between Action and EventHandler that comes into my mind is that we don't pass the sender and we don't have to create EventArgs classes.

public class Test
{
    public event Action<bool>? Connected;

    public ValueTask StartAsync()
    {
        Connected?.Invoke(true);
    }
}

var test = new Test();

test.Connected += async (boolean) => // private void OnConnect(bool boolean)
{
    await SendAsync(); // fire and forget
};

await test.StartAsync();
nop
  • 4,711
  • 6
  • 32
  • 93
  • Somewhat related: [How do I await events in C#?](https://stackoverflow.com/questions/27761852/how-do-i-await-events-in-c) – Theodor Zoulias Mar 30 '22 at 07:40
  • @TheodorZoulias, I think so, but I don't understand why Peter Duniho's answer made it so complicated. Perhaps the reason is that the guy wanted to have the instance of the sender and the EventArgs? Wouldn't my code in the question still work and keep track of the awaited calls, i.e. the opposite of fire and forget? – nop Mar 30 '22 at 07:50
  • ...if there's none define your own `delegate` that returns a task and takes event args or not? like: `public delegate Task AsyncEventHandler(object? sender, TEventArgs e);` – Patrick Beynio Mar 30 '22 at 07:59
  • @PatrickBeynio, why do I need the sender or EventArgs? Is it important? All I need is `public event Func? Disconnected`, `public event Func? Connected`. I don't need the sender/EventArgs for what I'm trying to accomplish. How important is it to me? Are there any benefits out of it? – nop Mar 30 '22 at 08:10
  • @nop it's usually used in when firing events from UI to pass the UI "invoked" element, but if you don't need it you could leave it out. – Patrick Beynio Mar 30 '22 at 08:19
  • @PatrickBeynio, that means I could leave `return Task.WhenAll(handlers.GetInvocationList() .OfType>() .Select(h => h(source, args)));` out of my code? If so, you can write it as an answer. – nop Mar 30 '22 at 08:23
  • 2
    It's because the `Connected?.Invoke()` will return the `Task` returned by the last event handler subscribed to the event. That's how events work. So if you want to cover the case of multiple subscribers, you must go down the rabbit hole of the `GetInvocationList()`, otherwise the `await` might return while a subscribed handler is still in-flight. – Theodor Zoulias Mar 30 '22 at 08:36
  • @TheodorZoulias, that's a satisfying explanation, thank you! You can type it as answer. – nop Mar 30 '22 at 09:02
  • 1
    If this information satisfies the question, then we should be able to find a similar question with an answer that includes this information, like [this](https://stackoverflow.com/questions/22523057/await-on-event-handler). In that case you can mark it as a duplicate if you want. – Theodor Zoulias Mar 30 '22 at 09:20

0 Answers0