Reputation: 663
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);
}
Upvotes: 1
Views: 1012
Reputation: 11444
As mentioned in other answers, you can structure your event handlers correctly so that this is not raised, as the runtime will know how to correctly call the delegate. Here is some code showing you how to structure this:
Expose a public Command to your view
public ICommand CopyDeviceId { get; private set; }
Then, create a command instance with a delegate
CopyDeviceId = new Command(() => CopyDeviceIdValue(this, EventArgs.Empty));
Finally, create the asyncronous delegate
private async void CopyDeviceIdValue(object sender, EventArgs e)
{
\\code here
}
Upvotes: 0
Reputation:
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.
Upvotes: 1
Reputation: 555
Async methods always should return a Task. A Task represents an action that has not finished yet. Afterwards you can do a Wait() on a task, to get the finished result... since your method is Void, you won't do any wait. The signature should look like this:
async Task HandleWidget_ClickButton (int id)
If you wanted to return something, it would be like this (for example, int):
async Task<int> HandleWidget_ClickButton (int id)
Upvotes: 1