与同步方法的接口与异步实现:干净的解决方法?

时间:2016-01-11 07:51:55

标签: c# asynchronous async-await

假设您有一个只有同步方法或属性的设置界面。

您必须实现这个简单的界面,因为这是某些图书馆希望您做的事情。

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()方法,我在代码中的某个点调用它。问题是,我的代码负责保存,而对于更复杂的界面,可能无法将所有内容保存在内存中。

这个问题最干净的解决方案是什么?有一个吗?

0 个答案:

没有答案