【问题标题】:using await inside properties in C# [duplicate]在 C# 中使用 await 内部属性 [重复]
【发布时间】:2012-11-23 11:30:41
【问题描述】:

可能重复:
How to call an async method from a getter or setter?

我正在尝试实现一个将在其中使用 Sqlite 等待的属性:

public int ID {
        get
        {
            if (_id != null)
            {
                return _id;
            }
            if (string.IsNullOrEmpty(ImageName))
            {
                return -1;
            }
            var query = CurrentConnection.Table<Image>().Where(i => i.ImageName == ImageName);
            var result = await query.ToListAsync();
            ...other code

但是,由于属性未设置为 await(尝试过,不起作用),我不能在属性中使用 await。

除了使用方法而不是属性之外,还有什么方法可以解决这个问题?

【问题讨论】:

  • 只需使用同步版本。
  • 你有一个递归错误。应该是if(_id != null) return _id; 而不是ID
  • 我希望属性小而快。如果你问我,任何涉及等待的事情都应该有一个方法。只是说...
  • 如果您有一个名为blahTask&lt;T&gt;,您可以致电blah.GetAwaiter().GetResult()。 -- 但这会阻塞当前线程 -- 除非它是您正在等待的超快速代码,否则我会强烈考虑其他选择。

标签: c# .net async-await c#-5.0


【解决方案1】:

没有技术原因在 C# 中不允许使用 async 属性。这是一个有目的的设计决策,因为“异步属性”是矛盾的。

属性应该返回当前值;他们不应该启动后台操作。

通常,当有人想要一个“异步属性”时,他们真正想要的是以下之一:

  1. 返回值的异步方法。在这种情况下,请将属性更改为 async 方法。
  2. 可用于数据绑定但必须异步计算/检索的值。在这种情况下,对包含对象使用async 工厂方法或使用async InitAsync() 方法。在计算/检索该值之前,数据绑定值将是 default(T)
  3. 创建成本高,但应缓存以备将来使用的值。在这种情况下,请使用 AsyncLazy from my blogAsyncEx library。这将为您提供awaitable 属性。

【讨论】:

    【解决方案2】:

    除了返回变量值之外,您不应该将属性 Getter 用于任何事情。

    调用代码通常会对调用类时的预期做出性能方面的假设。

    经验法则:

    • 属性意味着非常快速返回值
    • 方法或多或少意味着冗长的操作

    因此强烈建议不要将任何冗长的逻辑放入 getter。改用方法。

    微软的 Rico Mariany 在这里给出了一篇非常详细的文章:Performance Guidelines for Properties

    【讨论】:

    • Service Fabric 有异步字典来获取状态对象——速度非常快,而且它们在代码示例中的所有地方都可以做到。 -- 似乎 90% 的时间它是一个非常非常便宜的操作。 ——但要编写的代码比获取属性要多得多。 ——需要有一个解决方案。 :(
    • @BrainSlugs83:我是否理解正确,因为您不喜欢微软实施的可靠收集...?
    【解决方案3】:

    如果你使用 await,你会将方法的其余部分转换为回调,这意味着你不能返回一个 int。您需要返回一个 Task。目前也不支持在属性中使用 await,您需要将属性转换为返回 Task 的“get”方法。

    如果你想直接返回int,而不是等待awaitable,使用awaitable.Result。这将导致异步操作同步解析,允许您直接返回具体结果。

    【讨论】:

    • 然而,在属性 getter 内执行数据库查询通常被认为是一个糟糕的主意。属性 getter 应该快速而简单。
    • 这取决于该物业的主要用途是什么。如果对象是 DbLoggedInUser 并且属性是 FirstName,那么属性在后台执行数据库查询似乎是合理的。但是你是对的,一般来说属性应该是简单的并且不能失败。
    • 在属性的 getter 的后台进行数据库查询似乎是不合理的。 ——那就错了。 -- 那需要是一个方法调用。
    【解决方案4】:

    不 - 没有异步属性之类的东西。即使您可以声明一个异步属性,它也必须声明为返回值为Task&lt;int&gt; 而不是int...否则当您点击一个await 表达式?

    我会强烈在此处建议GetIdAsync 方法,假设您肯定想要异步行为。

    【讨论】:

    • 另请注意,如果它是Task&lt;int&gt; 类型的属性,它会使设置器真的变得怪异。
    • 由于 async/await 不能与 yield return 块一起使用,一个明智的折衷办法是手动实现 IEnumerator>,其中 Current 属性是 async。不能在属性上使用异步的这条规则是一种风格约束,它排除了这种有用的模式。现在唯一的解决方案是向客户端公开内部迭代细节,以便他们可以手动执行迭代。太可怕了。
    猜你喜欢
    • 1970-01-01
    • 2023-04-09
    • 2017-07-05
    • 2018-08-18
    • 2020-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-28
    相关资源
    最近更新 更多