使用Async实现延迟加载属性

9

我已经学会了在仓库中延迟加载属性。现在我想这样做,但我还需要从网页(使用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;
    }
}

然而,Visual Studio告诉我:

"此项不支持修饰符async"

并在第一行中突出显示单词“News”。

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


你已经使用了System.Threading.Tasks的using语句了吗?此外,这个程序是针对哪个.NET框架的?是Silverlight吗?--算了,我刚看到这是一个属性。你需要将其转换为方法。 - Ben H
在我看来,属性“News”直观上应该具有类型“List<NewsModel>”,在这里使用“Task<>”修饰似乎不太自然。你为什么觉得需要暴露“Task<>”的特性呢? - Andrew Coonce
@AndrewCoonce 实际上,如果他想编写一个异步方法,他肯定必须将其编写为返回任务。 - Lasse V. Karlsen
因为Visual Studio告诉我要这样做 :( 这是我第一次在C#中处理异步操作。 - Saturnix
@LasseV.Karlsen:是的,但这不是一个方法...这是一个属性。我想我的担忧是最终用户并没有期望副作用、异步操作等等...他们期望的是新闻项目的枚举。 - Andrew Coonce
显示剩余2条评论
4个回答

14

不支持异步属性。我在我的博客上描述了一些解决方法

在你的情况下,听起来异步延迟初始化会是一个很好的解决方案(也在我的博客中描述)。


9
首先,具有副作用的属性通常并不是很好的选择。
在这种情况下,仅仅读取这个属性就会启动一个线程、一些网络流量和远程服务器上的一些处理。
这应该是一个方法,而不是一个属性。
其次,编译器是正确的,属性不允许是异步的。现在,你肯定可以编写一个返回异步任务的属性,但是你不能使用 async 关键字。基本上只需要从属性声明中去掉 async 关键字即可。
但是 async 不允许在属性上使用,这是另一个提示,你应该编写一个方法,而不是一个属性。 注意 你发布的代码实际上并不需要 async 关键字,因为你实际上没有在其中使用 await 关键字。因此,你可以完全删除 async 关键字,因为它不是必需的。事实上,如果你将其改为方法,编译器将告诉你它是不必要的,因为你没有使用 await (在 OP 编辑问题后已删除。)

好的,你仍然不能使用“async”编写属性,因此“await”也必须去掉。 - Lasse V. Karlsen
那我是应该删除整个属性,改为编写一个方法吗?顺便感谢您的帮助 :) - Saturnix
该操作者的代码不会启动另一个线程。此外,使用“async”方法也不是很合适,因为该操作者只希望网络请求发生一次。 - Stephen Cleary
2
首先,具有副作用的属性通常并不是很好的选择 - 当然,并不包括那些采用代理类以及按需/延迟加载的ORM中使用的情况。 - user585968
2
我同意“具有副作用的属性通常并不是很好”的说法,但我认为这并不适用于这里。属性不应该改变系统的逻辑状态。我认为加载数据不是一种副作用。查询属性就像是在问一个问题,而努力回答这个问题是一种预期的效果。 - Hypnovirus
显示剩余4条评论

4
您可以使用返回Task的Lazy属性:
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;
       //...
    }
}

1
在我看来,这使得Lazy变得无用,在这种情况下,Lazy只会初始化任务,而这在大多数情况下并不是你想要的。 - Arsen Mkrtchyan

1
我认为这个问题是相关的。
简而言之,异步属性不受支持。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接