Ale*_*kiy 3 c# wpf wcf asynchronous async-await
我有一个Singleton(好吧,它可以是一个静态类,无所谓),这是我的WPF应用程序的一些数据的外观.我想通过WCF加载此数据异步.这是我的实现:
public class Storage
{
private static readonly Lazy<Storage> _lazyInstance = new Lazy<Storage>(()=>new Storage());
public static Storage Instance
{
get { return _lazyInstance.Value; }
}
private Storage()
{
Data = new Datastorage(SettingsHelper.LocalDbConnectionString);
InitialLoad().Wait();
}
public Datastorage Data { get; private set; }
private async Task InitialLoad()
{
var tasks = new List<Task>
{
InfoServiceWrapper.GetSomeData()
.ContinueWith(task => Data.StoreItem(task.Result)),
InfoServiceWrapper.GetAnotherData()
.ContinueWith(task => Data.StoreItem(task.Result)),
InfoServiceWrapper.GetSomeMoreData()
.ContinueWith(task => Data.StoreItem(task.Result)),
};
await Task.WhenAll(tasks.ToArray());
}
}
Run Code Online (Sandbox Code Playgroud)
我从我的ViewModel访问这个类,如下所示:
public class MainWindowViewModel:ViewModelBase
{
public SensorDTO RootSensor { get; set; }
public MainWindowViewModel()
{
var data = Storage.Instance.Data.GetItem<SensorDTO>(t=>t.Parent==t);
RootSensor = data;
}
}
Run Code Online (Sandbox Code Playgroud)
在我看来,我有RootSensor的绑定.一切都很好,但我有一个问题:所有我的异步代码执行,然后我发现死锁InitialLoad().Wait();
.我知道它涉及WPF UI线程,但不明白如何解决这个问题.
我会感激任何帮助!
您基本上遇到了异步/等待的限制:构造函数不能标记为异步.解决问题的正确方法不是通过Wait
构造函数调用.这是作弊 - 它会阻止,使你所有的好的异步都变得没有意义,更糟糕的是它会在你发现时引发死锁.
正确的方法是重构您的Storage
类,以确保所有异步工作都是从异步方法而不是构造函数完成的.我建议通过用方法替换你的Instance
属性来做到这一点GetInstanceAsync()
.由于这是获取单例实例的唯一公共接口,因此您将确保始终调用InitialLoad
(我将重命名InitialLoadAsync
).
public class Storage
{
private static Storage _instance;
public static async Task<Storage> GetInstanceAsync()
{
if (_instance == null)
{
// warning: see comments about possible thread conflict here
_instance = new Storage();
await _instance.InitialLoadAsync();
}
return _instance;
}
private Storage()
{
Data = new Datastorage(SettingsHelper.LocalDbConnectionString);
}
// etc
}
Run Code Online (Sandbox Code Playgroud)
现在,你如何在没有阻塞的情况下Storage.GetInstanceAsync()
从MainWindowViewModel
构造函数调用?你可能已经猜到了,你做不到,所以你需要同样地重构它.就像是:
public class MainWindowViewModel : ViewModelBase
{
public SensorDTO RootSensor { get; set; }
public async Task InitializeAsync()
{
var storage = await Storage.GetInstanceAsync()
RootSensor.Data.GetItem<SensorDTO>(t=>t.Parent==t);
}
}
Run Code Online (Sandbox Code Playgroud)
当然,无论什么电话都await MainWindowViewModel.InitializeAsync()
需要被标记async
.async/await据说通过你的代码像僵尸病毒一样传播,这很自然.如果在调用堆栈中的任何地方你用一个.Wait()
or 打破了那个循环.Result
,你就会遇到麻烦.
归档时间: |
|
查看次数: |
2405 次 |
最近记录: |