【问题标题】:Async void on subscribed Prism methods订阅的 Prism 方法上的异步无效
【发布时间】:2021-03-01 22:27:55
【问题描述】:

我知道您应该尽量不要使用async void,事件处理程序除外。事件处理程序的例外是否包括 Prism 事件?我下面的例子可以吗?

模块 A 的视图有一个 DataGrid,当用户单击记录时它会发布 SelectionChangedEvent,该事件在模块 B 中订阅,可能需要一段时间才能完成。

    public class ModuleA 
    {
        private ObservableCollection<Company> carCollectionOC = new ObservableCollection<Company>();        

        private void CarCollection_CurrentChanged(object sender, EventArgs e)
        {
            Company company = (Company)(sender as ICollectionView).CurrentItem;
            this.eventAggregator.GetEvent<SelectionChangedEvent>().Publish(company.Brand);
        }  
    }

模块 B 订阅并执行async void

public class ModuleB 
{
        private ObservableCollection<Vehicle> vehicleOC = new ObservableCollection<Vehicle>();
        private VehicleService vehicleService;

        public ModuleB(IEventAggregator eventAggregator)
        {
            this.vehicleService = new VehicleService();                    
            this.eventAggregator.GetEvent<SelectionChangedEvent>()
                          .Subscribe(this.SubscribedMethod,
                          ThreadOption.UIThread,
                          false);
        }

        private async void SubscribedMethod (string brand)
        {
            this.vehicleOC = await this.GetData(brand);
        }

        private List<Vehicle> GetVehicles(string carBrand)
        {
            Console.WriteLine("finishing GetVehicles");
            return this.vehicleService.GetVehicleList(carBrand);
        }

        private async Task<ObservableCollection<Vehicle>> GetData(string carBrand)
        {
            vehicleListFromService = await Task.Run(() => this.GetVehicles(carBrand));
            
            this.vehicleOC.Clear();
            foreach (var vehicle in vehicleListFromService)
                this.vehicleOC.Add(vehicle);

            return this.vehicleOC;

        }        
}

【问题讨论】:

  • Subscribe 中使用的方法不是订阅方法,而是订阅方法。订阅的是一个事件。因此,事件聚合器。

标签: c# wpf async-await prism


【解决方案1】:

当然,即使是斯蒂芬(就我而言,这方面的权威)也清楚地说:

总结第一个准则,您应该更喜欢 async Task 异步无效。异步任务方法使错误处理更容易, 可组合性和可测试性。本指南的例外是 异步事件处理程序,必须返回 void。这个例外 包括逻辑上是事件处理程序的方法,即使它们不是 字面上的事件处理程序(例如,ICommand.Execute 实现)。

https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming

就个人而言,我总是将async void 方法的内容包装在try-catch 中并处理异常,而不管方法的内容如何。我编写了一个简单的帮助类来帮助解决这个问题。

【讨论】:

  • 虽然确实应该总是更喜欢async Task 而不是async void,但我想说给PubSubEvent.Subscribe 一个接受真正async Task 处理程序的重载会比创可贴包装纸。这不是原生 .Net 事件,我们可以修改代码(或者更确切地说,使用自己的 PubSubEvent 变体创建对 async Task 的订阅)...
【解决方案2】:

事件处理程序的例外是否包括 Prism 事件?

是的。订阅者必须是Action,即void MyHandler()(或async void MyHandler())。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多