【问题标题】:Lazy load properties with Async使用异步延迟加载属性
【发布时间】:2013-08-01 06:53:34
【问题描述】:

我学会了在我的存储库中延迟加载属性。现在我想这样做,但我还需要从网页加载一些东西(使用 Httpclient),这意味着我的属性将是异步的。

public async Task<List<NewsModel>> News
{
    get
    {
        if (_news == null)
        {
            CacheProvider cache = new CacheProvider();
            object cachedNews = cache.Get("news");

            if (cachedNews == null)
            {
                var client = new HttpClient();
                // await HttpResponse
            }

        }
        return _news;
    }

    set
    {
        _news = value;
    }
}

然而,视觉工作室告诉我

“修饰符 async 对此项无效”

同时突出显示第一行中的“新闻”一词。

可以这样做吗?还是我必须写一个单独的方法?

【问题讨论】:

  • 我认为您有 System.Threading.Tasks 的 using 语句?另外,这是针对哪个 .NET 框架?是银光吗? -- 没关系,只是看到这是一个属性。您需要将其转换为方法。
  • 在我看来,News 属性直观上会具有 List&lt;NewsModel&gt; 类型,Task&lt;&gt; 装饰在这里看起来并不自然。为什么你觉得有必要暴露Task&lt;&gt;的本质?
  • @AndrewCoonce 其实如果他想写一个异步方法,他肯定要写成返回任务。
  • 因为 Visual Studio 告诉我这样做 :( 我第一次在 C# 中处理异步。
  • @LasseV.Karlsen:是的,但这不是一种方法……这是一种属性。我想我担心的是最终用户不会期待副作用、异步操作等......他们期待新闻项目的枚举。

标签: c# asynchronous


【解决方案1】:

不支持异步属性。我在我的博客上描述了number of workarounds

在您的情况下,听起来asynchronous lazy initialization 将是一个很好的解决方案(也在我的博客中进行了描述)。

【讨论】:

    【解决方案2】:

    首先,具有副作用的属性通常不是那么好。

    在这种情况下,只需读取此属性即可启动线程、一些网络流量以及远程服务器上的一些处理。

    这应该是一个方法,而不是一个属性。

    其次,编译器是对的,属性是不允许异步的。现在,您绝对可以编写一个返回异步任务的属性,但不允许使用async 关键字。基本上只是从属性声明中去掉async关键字。

    但是async 在属性上是不合法的事实是另一个线索,你应该编写一个方法,而不是一个属性。

    注意 async 关键字在您发布的代码中实际上不是必需的,因为您实际上并没有在其中使用 await 关键字。因此,您可以简单地完全删除 async 关键字,因为它不是必需的。实际上,如果您要将其更改为方法,编译器会告诉您这是不必要的,因为您没有使用await (在 OP 编辑​​问题后删除。)

    【讨论】:

    • 哦等等!我正在使用等待! httpclient 将像这里的人一样使用 await:stackoverflow.com/questions/7929013/…
    • 如果我删除“等待”,我必须将 HttpResponseMessage 包装在一个任务中——这意味着我必须在代码中的某处写一个“等待”...
    • 好吧,你还是不能用async写属性,所以await也得去。
    • “首先,具有副作用的属性通常不是那么好” - 不,这就是 proxy classeson-demand/lazy-load 加载工作,例如在 ORMs
    • 我同意“具有副作用的属性通常不是那么好”,但我认为它不适用于这里。属性不应改变系统的逻辑状态。我不认为加载数据是副作用。查询属性就是提出问题。努力回答问题是预期的效果。
    【解决方案3】:

    您可以使用返回任务的延迟属性:

    class MyClass
    {
        readonly Lazy<Task<string>> _text;
    
        public MyClass()
        {
            _text = new Lazy<Task<string>>(async () =>
            {
                //... await something
                return "Hello!"
            });
        }
    
        async Task DoSomething()
        {
           var text = await _text.Value;
           //...
        }
    }
    

    【讨论】:

    • 恕我直言,这让 Lazy 无用,在这种情况下,Lazy 只会初始化任务,大多数情况下这不是你想要的
    【解决方案4】:

    我认为this question 是相关的。

    简而言之 - 不支持异步属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-17
      • 2017-12-28
      • 2016-09-13
      • 1970-01-01
      • 2019-08-06
      • 2013-07-03
      • 2014-07-26
      相关资源
      最近更新 更多