Gerhard Schreurs Gerhard Schreurs - 12 days ago 7
C# Question

Can I refactor code to fix "Asynchronous method should not return void"?

I am doing a project in c# using Xamarin. The compiler warns me that "Asynchronous method 'HandleWidget_ClickButton' should not return void". See example here:

//Code is simplified

public class Widget {
public event Action<int> ClickButton;

private void FireClickButton (int id)
{
if (ClickButton != null) {
ClickButton (id);
}
}

//somewhere else i call FireClickButton(1);
}

public class MyFragment {
private _widget Widget;

public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
//...
_widget = view.FindViewById<Widget> (Resource.Id.widget);
//...
}


public override void OnResume ()
{
base.OnResume ();
_widget.ClickButton += HandleWidget_ClickButton;
}

async void HandleWidget_ClickButton (int id)
{
await SaveSomethingInStorage (id);
}
}


Can I somehow return something to an event/action/delegate? I do not know if this is possible, or how to write this, syntax-wise, and I've spent quite some time searching for a solution. Elsewhere I read that when handling events, it's ok to use async void (instead of something like async Task), but I like to avoid warnings and do not like to hide them using #Pragma instructions.

EDIT (With answer) from @hvd:

"You created an event handler, but you don't follow the .NET conventions for event handlers. You should. The warning is automatically suppressed for what can be detected as event handlers.

The .NET conventions for event handlers require a sender, of type object, and the event arguments, of type EventArgs or a class derived from EventArgs. If you use this signature, you should no longer get a warning."

I rewrote my code like this:

public class MyEventArgs : EventArgs
{
public MyEventArgs (int id)
{
ID = id;
}

public int ID;
}

public class Widget {
public event EventHandler<MyEventArgs> ClickTest;

void FireClickButton (int id)
{
if (ClickTest != null) {
ClickTest (this, new MyEventArgs (id));
}
}
}

//In observer class
_widget.ClickTest += HandleWidget_ClickTest;

async void HandleWidget_ClickTest (object sender, MyEventArgs e)
{
await DoSomethingAsync (e.ID);
}


Note that you must derive from EventArgs. Doing it like this does not suppress the warning:

public event EventHandler<int> AnotherClickTest;

if (AnotherClickTest != null) {
AnotherClickTest (this, 1);
}

hvd hvd
Answer

You created an event handler, but you don't follow the .NET conventions for event handlers. You should. The warning is automatically suppressed for what can be detected as event handlers.

The .NET conventions for event handlers require a sender, of type object, and the event arguments, of type EventArgs or a class derived from EventArgs. If you use this signature, you should no longer get a warning.

Comments