使用异步延迟加载属性

问题描述 投票:0回答:4

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

然而,视觉工作室告诉我

“修饰符异步对此项目无效”

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

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

c# asynchronous
4个回答
14
投票

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

就您而言,听起来异步延迟初始化将是一个很好的解决方案(我的博客上也有描述)。


9
投票

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

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

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

其次,编译器是对的,属性不允许异步。现在,您绝对可以 write 返回异步任务的属性,但不允许使用

async
关键字。基本上只需从属性声明中删除
async
关键字即可。

但是

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

注意 您发布的代码中实际上并不需要

async
关键字,因为您实际上并未在其中使用
await
关键字。因此,您可以简单地完全删除
async
关键字,因为它不是必需的。事实上,如果你要把它改成一个方法,编译器会告诉你这是不必要的,因为你没有使用
await
(OP编辑问题后删除。)


4
投票

您可以使用返回任务的 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;
       //...
    }
}

更新: 请注意,

Lazy
在内部使用
Monitor.Enter
,因此同时从多个线程访问它可能会导致拒绝服务。我已经使用
SemaphoreSlim
实现了 Lazy 的基本实现,这将使线程在等待值时保持可用。请参阅我的要点这里


1
投票

我认为这个问题是相关的。

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

© www.soinside.com 2019 - 2024. All rights reserved.