Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步/等待-何时返回任务vs void?_C#_Asynchronous_.net 4.5 - Fatal编程技术网

C# 异步/等待-何时返回任务vs void?

C# 异步/等待-何时返回任务vs void?,c#,asynchronous,.net-4.5,C#,Asynchronous,.net 4.5,在什么样的情况下你会想使用它 public async Task AsyncMethod(int num) 而不是 public async void AsyncMethod(int num) 我能想到的唯一情况是,如果您需要任务来跟踪其进度 此外,在下面的方法中,是否不需要async和await关键字 public static async void AsyncMethod2(int num) { await Task.Factory.StartNew(() => Threa

在什么样的情况下你会想使用它

public async Task AsyncMethod(int num)
而不是

public async void AsyncMethod(int num)
我能想到的唯一情况是,如果您需要任务来跟踪其进度

此外,在下面的方法中,是否不需要async和await关键字

public static async void AsyncMethod2(int num)
{
    await Task.Factory.StartNew(() => Thread.Sleep(num));
}
  • 通常,您希望返回一个
    任务
    。主要的例外情况应该是当您需要一个
    void
    返回类型(对于事件)时。如果没有理由不允许调用方等待您的任务,为什么不允许

  • 返回
    void
    async
    方法在另一个方面是特殊的:它们表示顶级异步操作,并具有在任务返回异常时起作用的附加规则。最简单的方法是通过一个示例来说明差异:

  • f
    的异常总是“被观察到”。离开顶级异步方法的异常与任何其他未处理的异常一样简单处理
    g
    的异常从未被观察到。当垃圾收集器来清理任务时,它看到任务导致了异常,并且没有人处理该异常。发生这种情况时,
    TaskScheduler.UnobservedTaskException
    处理程序将运行。你不应该让这种事情发生。以你为例,

    public static async void AsyncMethod2(int num)
    {
        await Task.Factory.StartNew(() => Thread.Sleep(num));
    }
    
    是的,在这里使用
    async
    wait
    ,它们可以确保在抛出异常时方法仍然正常工作


    有关更多信息,请参阅:

    我遇到了这篇非常有用的文章,内容是关于Jérôme Laban撰写的
    async
    void

    底线是
    async+void
    可能会使系统崩溃,通常只应在UI端事件处理程序上使用

    这背后的原因是 AsyncVoidMethodBuilder,在本例中为无。当没有 环境同步上下文,未处理的任何异常 异步void方法的主体在线程池上重新引用。虽然 似乎没有其他合乎逻辑的地方可以解决这种问题 异常可能被抛出,不幸的结果是进程 正在终止,因为线程池上存在未处理的异常 从.NET 2.0起有效终止进程。你可以拦截 使用AppDomain.UnhandledException事件的所有未处理异常, 但无法从该事件中恢复进程

    在编写UI事件处理程序时,异步void方法以某种方式 无痛,因为异常的处理方式与 非异步方法;他们被扔到调度员身上。有一个 从此类异常中恢复的可能性非常正确 在大多数情况下。但是,在UI事件处理程序之外,async void 方法使用起来有点危险,可能不那么容易找到


    我认为您也可以使用
    async void
    启动后台操作,只要您小心捕获异常。想法

    class Program {
    
        static bool isFinished = false;
    
        static void Main(string[] args) {
    
            // Kick off the background operation and don't care about when it completes
            BackgroundWork();
    
            Console.WriteLine("Press enter when you're ready to stop the background operation.");
            Console.ReadLine();
            isFinished = true;
        }
    
        // Using async void to kickoff a background operation that nobody wants to be notified about when it completes.
        static async void BackgroundWork() {
            // It's important to catch exceptions so we don't crash the appliation.
            try {
                // This operation will end after ten interations or when the app closes. Whichever happens first.
                for (var count = 1; count <= 10 && !isFinished; count++) {
                    await Task.Delay(1000);
                    Console.WriteLine($"{count} seconds of work elapsed.");
                }
                Console.WriteLine("Background operation came to an end.");
            } catch (Exception x) {
                Console.WriteLine("Caught exception:");
                Console.WriteLine(x.ToString());
            }
        }
    }
    
    类程序{
    静态bool isFinished=false;
    静态void Main(字符串[]参数){
    //启动后台操作,不关心它何时完成
    背景();
    WriteLine(“准备好停止后台操作时按enter键”);
    Console.ReadLine();
    isFinished=true;
    }
    //使用async void启动后台操作,该操作完成时没有人希望得到通知。
    静态异步void BackgroundWork(){
    //捕获异常非常重要,这样我们就不会使应用程序崩溃。
    试一试{
    //此操作将在十次迭代后或应用程序关闭时结束。以先发生的为准。
    
    对于(var count=1;count调用async void的问题是

    您甚至无法收回任务。您无法知道函数的任务何时完成。-

    以下是调用异步函数的三种方法:

    async Task somethingsync(){…return t;}
    异步任务SomethingAsync(){…}
    异步void SomethingAsync(){…}
    
    在所有情况下,函数都被转换为一系列任务。不同之处在于函数返回的内容

    在第一种情况下,函数返回一个最终生成t的任务

    在第二种情况下,函数返回一个没有产品的任务,但您可以 仍在等待它知道它何时运行完成

    第三种情况是令人讨厌的。第三种情况与第二种情况相似,除了 你甚至连任务都拿不回来你不知道什么时候 该函数的任务已完成

    async void案例是一个“火灾和火灾”案例 忘记”:你启动了任务链,但你不在乎它何时启动 完成。当函数返回时,您只知道 直到第一次等待已经执行。第一次等待之后的一切 将在将来的某个未指定的点运行,而您没有 访问

    我的答案很简单 你不能等待无效的方法

    Error   CS4008  Cannot await 'void' TestAsync   e:\test\TestAsync\TestAsyncProgram.cs
    
    因此,如果该方法是异步的,最好等待,因为您可能会失去异步优势。

    ,永远不要使用
    async void

    不要这样做:下面的示例使用
    async void
    ,它使 到达第一个等待时HTTP请求完成:

    • 这在ASP.NET核心应用程序中始终是一种不好的做法

    • 在HTTP请求完成后访问HttpResponse

    • 使过程崩溃


    我在评论中的意思是
    f
    而不是
    g
    。来自
    f
    的异常被传递到
    SynchronizationContext
    g
    将引发
    unobservedtaskeexception
    ,但是
    UTE
    如果未处理,将不再使进程崩溃。在某些情况下,可以接受异常像这样的“异步异常”会被忽略
    async Task<T> SomethingAsync() { ... return t; }
    async Task SomethingAsync() { ... }
    async void SomethingAsync() { ... }
    
    Error   CS4008  Cannot await 'void' TestAsync   e:\test\TestAsync\TestAsyncProgram.cs