4

Is there any point in wrapping event assignments in anonymous async functions?

Lets say this code is in some adapter class:

public event Action<int> someAction;

The following code is in some other class that sets the action:

Example 1:

_someAdapter.someAction += async (someParameter) =>
{
    await HandleAction(someParamter);
};

In this case HandleAction has async Task return type.

Example 2:

_someAdapter.someAction += HandleAction;

In this case HandleAction has async void return type.

The same question applies to button click event handlers etc. I have seen examples of both and was wondering why this gets wrapped sometimes. From my testing there doesn't seem to be any difference.

axlrtr
  • 535
  • 6
  • 23
  • I think, it may have sense when some event handler can be time-consumable. Try to insert `Sleep(1000)` in your test, this can show a difference. – Miamy Nov 18 '18 at 20:54

4 Answers4

2

I believe that using an anonymous handler wrapper you'll be able to let the C# Garbage Collector just "unhook" and destroy the handler on this (on example 1) when it is about to be destroyed.

Event handlers outside the this (it isn't the case in your example) would have special attention and wrap it looks a good choice.

If this will live a long time and there is some possibility of you have to hook that event again you should use another strategy to avoid memory leak like ones discussed on this question

The return types differences are related to exception handling and it's ok to use an async void on top-level methods and async event handlers.

I hope it helps.

Diego Rafael Souza
  • 5,241
  • 3
  • 23
  • 62
1

In your example, there would be likely be no noticeable difference. This is more about coding standards and best practices. In general, it is not recommended that you create 'async void' functions, if you can avoid it. The purpose of that feature is to allow async code in functions that can't change their signature (like overrides). An 'async void' function has disadvantages like swallowing exceptions and being less composable.

If, for instance, you wanted to call HandleAction from another place/method (often this is the reason for using a named method instead of an anonymous function), you would not be able to await it unless it returns Task.

Also, if HandleAction threw an exception, you would not be able to catch it if you can't await it, so you better be sure it will handle all exceptions internally.

Ben Reierson
  • 1,099
  • 6
  • 8
1

I won't recommend to use an anonymes delegate as an event handler. The reason is that it might come to cycling references and thus the garbage collector won't be able to free up memory - so called memory leak.

Especially in the Xamarin-world, where the managed garbage collector often won't know the real size of an object, developers should have an eye on memory and allocations their applications needs.

By avoiding anonymes delegates you are able to break the cycle simple by removing the event handler assignment.

tequila slammer
  • 2,821
  • 1
  • 18
  • 25
0

I can't comment on your adapter handlers, but... seeing as you say "The same question applies to...", the answer might be the same as for button click event handlers, etc, which is (arguably the largest benefit of async in UI applications) - you get to perform expensive async operations in the handlers off the UI thread.

E.g.

_button.Click += async (...) =>
{
    int answer = await ExpensiveHttpResultThatTakes10Seconds();
    _answer.Text = answer.ToString();
};

If that wasn't async, the UI would freeze up for 10 seconds, not responding to clicks, keys, etc.

Because it is async, the UI remains responsive during those 10 seconds, as the await is non-blocking, processing UI events and even other event handlers.

sellotape
  • 8,034
  • 2
  • 26
  • 30
  • Yes, but if you only did that ExpensiveHttpResultThatTakes10Seconds method, I don't think there would be any difference in writing _button.Click += ExpensiveHttpResultThatTakes10Seconds and wrapping it in an async function. The wrapping async function returns void after all, which I believe would be equal to ExpensiveHttpResultThatTakes10Seconds having void. In your case you are doing 2 things so that's different. – axlrtr Nov 18 '18 at 21:38
  • @axlrtr - perhaps I misunderstood your question... are you asking - in the context of UI events - why bother with making the event handler async when you can just have a sync event handler kick off a fire-and-forget `async void` method instead (assuming you don't need to interact with the UI context from that point onwards)? – sellotape Nov 19 '18 at 09:49