假设您有一个只有同步方法或属性的设置界面。
您必须实现这个简单的界面,因为这是某些图书馆希望您做的事情。
public interface ISettings
{
// This could also be a GetLoginName() and SetLoginName().
string LoginName { get; set; }
}
您的代码已经具有一些保存用户配置的功能,但它完全是异步的(可能使用某些异步数据库连接或将配置异步写入某些基于云的Web服务 - 无论如何)。您希望重复使用代码来实现ISettings
。
到目前为止,我们都知道阻止异步代码几乎总是deadlock的保证(只选择处理该问题的许多文章之一)。
那该怎么办?下面的天真方法可能会陷入僵局,所以不是一个真正的选择:
public class ConcreteSettings : ISettings
{
SqlConnectionAsync asyncConn;
// Async in properties is always bad, I know;
// props are meant to be fast-non-blocking as Damien correctly states.
// But the interface could also have a SetLoginName() and GetLoginName()
// method - same problem in the end.
public string LoginName
{
get
{
var t = this.asyncConn.Table<Config>().GetValueAsync("loginName");
// Bad idea because if GetValueAsync() wants to execute a continuation
// after its async code parts, it will deadlock.
return t.Result;
}
set
{
var t = this.asyncConn.InsertOrUpdateAsync("loginName", value);
// Same argument as above: this can deadlock.
t.Wait();
}
}
}
作为替代方案,我正在考虑强制执行线程池:
...
get
{
var t = Task.Run(async () => {
return await this.asyncConn.Table<Config>().GetValueAsync("loginName");
}).ConfigureAwait(false);
return t.Result;
}
...
这可以恕我直言 - 但它感觉非常俗气。
我的最后一个想法是使用一些内存中的属性来实现接口,然后在我的具体实现中添加一个异步PersistToDatabaseAsync()
方法,我在代码中的某个点调用它。问题是,我的代码负责保存,而对于更复杂的界面,可能无法将所有内容保存在内存中。
这个问题最干净的解决方案是什么?有一个吗?