RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1571123
Accepted
CrazyElf
CrazyElf
Asked:2024-03-12 01:24:56 +0000 UTC2024-03-12 01:24:56 +0000 UTC 2024-03-12 01:24:56 +0000 UTC

同步调用异步方法?

  • 772

这可能是重复的,但我找不到明确的答案。是的,许多食谱都是旧版本的.NET Framework,但在现代版本中.NET (Core)可能会发生一些变化。

因此,遗留代码包含如下结构:

FooAsync().Wait();
...
var result = BarAsync().Result;

在我看来,这种对异步方法的处理是不正确的。在某个地方,我设法将异步拖到所有级别,并通过await. 但不可能在所有地方都这样做;在顶层的某个地方,一切都依赖于同步代码,我不确定是否可以将其更改为异步。或者在更高的地方有很多层次的架构,我也无法一次全部改变。

那么,问题是:在现代版本中.NET如何建议从同步代码调用异步代码?我知道根本不建议这样做,但是对于无法避免这种情况的情况,最正确的方法是什么?还是只能接受现状,其他选择也好不到哪儿去?

PS 特别是,在类构造函数中调用异步方法存在问题。是的,有一些技术可以隐藏构造函数,但在我看来,它们不能与使用DI框架结合起来。例子:

public class Foo : IFoo
{
    public Foo(ISomething something, IAnother another)
    {
        _something = something;
        _another = another;
        Bar().Wait();
    }
}
...
serviceCollection.AddSingleton<ISomething, Something>();
serviceCollection.AddSingleton<IAnother, Another>();
serviceCollection.AddSingleton<IFoo, Foo>();
c#
  • 1 1 个回答
  • 96 Views

1 个回答

  • Voted
  1. Best Answer
    aepot
    2024-03-12T02:52:15Z2024-03-12T02:52:15Z

    事实上,异步同步唯一有效和使用的地方是main应用程序的入口点。但为了不让任何人感到困惑,.NET 开发人员已经实现了绑定,现在您可以简单地编写。

    static async Task Main(string[] args)
    {
        // await
    }
    

    这就是顶层。没有其他上层。

    当然,例如 Windows 窗体,其中底层事件处理程序不支持异步,例如

    private void Button_Click(object sender, EventArgs e)
    {
        // Foo();
    }
    

    但这里已经有现成的解决方案了。由于异步方法在运行时不会阻塞 UI,因此您应该保护按钮直到异步操作结束。另外,由于除了void从方法返回之外无法返回任何内容,因此需要捕获async void方法中的异常。

    private async void Button_Click(object sender, EventArgs e)
    {
        Button btn = (Button)sender;
        btn.Enabled = false;
        try
        {
            // await FooAsync();
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
        btn.Enabled = true;
    }
    

    事实上,这就是整个解决方案。根据定义,代码中不应该有任何.Wait()or 。.Result

    唯一允许提及.Result它的时候是它Task已经明确完成的时候,甚至在某些情况下这被认为是比 更健康的做法await,但这些都是微妙之处。

    if (task.IsCompleted)
    {
        var result = task.Result;
    }
    

    因此,如果你知道自己在做什么,那么你可以将其用作临时拐杖,.Wait()直到.Result你系统地完全重写它。

    在任何情况下都强烈建议不要仅仅因为似乎没有其他简单的解决方案而使用同步异步。因为在最好的情况下,这将是由于无意义的流程阻塞而浪费资源,在最坏的情况下,您将寻找仅在行星巡游期间满月时发生的死锁。


    PS 对于设计师来说,也有几种解决方案。其中一人“开枪后就忘记了”。

    private readonly _initTask;
    private string _superImportantValue;
    
    public Foo(ISomething something, IAnother another)
    {
        _something = something;
        _another = another;
        _initTask = Bar();
    }
    
    private async Task Bar()
    {
        await Task.Delay(1000);
        _superImportantValue = "ready";
    }
    

    现在我们需要处理使用它的方法中出现错误的概率_superImportantValue。

    选项 1 - 抛出异常

    public void Baz()
    {
        if (!_initTask.IsCompleted)
            throw new InvalidOperationException();
        // ... _superImportantValue
    }
    

    选项 2 - 仍然冻结

    public void Baz()
    {
        _initTask.Wait();
        // ... _superImportantValue
    }
    

    如果逻辑上假设在 99.9% 的情况下_initTask该方法在调用方法时已经准备好,则此选项是可以接受的。

    无论如何,如果这不是一个理想的解决方案,那么至少它不会阻止您在 IOC 容器中构建应用程序。

    选项 3 - 有可能吗?

    public async Task BazAsync()
    {
        await _initTask;
        // ... _superImportantValue
    }
    
    • 3

相关问题

  • 使用嵌套类导出 xml 文件

  • 分层数据模板 [WPF]

  • 如何在 WPF 中为 ListView 手动创建列?

  • 在 2D 空间中,Collider 2D 挂在玩家身上,它对敌人的重量相同,我需要它这样当它们碰撞时,它们不会飞向不同的方向。统一

  • 如何在 c# 中使用 python 神经网络来创建语音合成?

  • 如何知道类中的方法是否属于接口?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5