我可以重构代码来修复"异步方法不应该返回void"?

时间:2016-11-23 11:21:41

标签: c# asynchronous

我正在使用Xamarin在c#中做一个项目。编译器警告我"异步方法' HandleWidget_ClickButton'不应该返回无效"。见这里的例子:

//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);
    }
}

我可以以某种方式将某些内容返回给事件/动作/委托吗?我不知道这是否可行,或者如何写这个,语法方面,我花了很长时间寻找解决方案。在其他地方,我读到处理事件时,可以使用async void(而不是像async Task那样),但我喜欢避免警告而不喜欢使用#Pragma指令隐藏它们。

来自@hvd的

编辑(有答案)

  

您创建了一个事件处理程序,但您没有遵循.NET   事件处理程序的约定。你应该。警告是   自动抑制可以检测为事件处理程序的内容。

     

事件处理程序的.NET约定需要类型的发件人   对象和事件参数,类型为EventArgs或派生类   来自EventArgs。如果您使用此签名,则不应再获得此签名   警告。

我改写了我的代码:

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);
}

请注意,您必须从EventArgs派生。这样做不会抑制警告:

public event EventHandler<int> AnotherClickTest;

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

3 个答案:

答案 0 :(得分:2)

您创建了一个事件处理程序,但您没有遵循事件处理程序的.NET约定。你应该。对于可以检测为事件处理程序的内容,将自动禁止警告。

事件处理程序的.NET约定要求类型为object的发件人和类型为EventArgs的事件参数或源自EventArgs的类。如果您使用此签名,则不应再收到警告。

答案 1 :(得分:1)

异步方法总是应该返回一个Task。任务表示尚未完成的操作。之后你可以对任务执行Wait(),以获得完成的结果......因为你的方法是Void,你不会做任何等待。签名应如下所示:

async Task HandleWidget_ClickButton (int id)

如果你想要返回一些东西,就像这样(例如,int):

async Task<int> HandleWidget_ClickButton (int id)

答案 2 :(得分:0)

如其他答案中所述,您可以正确构造事件处理程序,以免引发事件处理程序,因为运行时将知道如何正确调用委托。这是一些代码,向您展示如何构建它:

向您的视图公开一个公共命令

public ICommand CopyDeviceId { get; private set; }

然后,使用委托创建命令实例

CopyDeviceId = new Command(() => CopyDeviceIdValue(this, EventArgs.Empty));

最后,创建异步委托

private async void CopyDeviceIdValue(object sender, EventArgs e)
{
    \\code here
}