简体   繁体   English

async Func 的 3 次调用有什么区别<task<t> &gt; 在 c# 中? </task<t>

[英]What are differences between the 3 calls for async Func<Task<T>> in c#?

What are differences between the 3 calls inside method WhatDifferences ?方法WhatDifferences中的 3 个调用之间有什么区别?

Here is test code:这是测试代码:

async Task WhatDifferences(Context context)
{
    await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
    await ActionAsync(context, x => IsOddAsync(x));
    await ActionAsync(context, IsOddAsync);
}

async Task<T> ActionAsync<T>(Context context, Func<Context, Task<T>> action)
{
    return await action(context).ConfigureAwait(false);
}

async Task<bool> IsOddAsync(Context context)
{
    return await Task.Run(() => context.Count++ % 2 == 1).ConfigureAwait(false);
}

class Context
{
    public int Count { get; set; }
}

I'm trying to decide which one to use in my codebase and based on my knowledge all 3 behave the same.我正在尝试决定在我的代码库中使用哪一个,并且根据我的知识,所有 3 个行为都相同。

The question is different with What's the method signature for passing an async delegate?问题与传递异步委托的方法签名不同?

You may know my concern if I show more logic如果我表现出更多的逻辑,你可能会知道我的担忧

async Task<T> ActionAsync<T>(Context context, Func<Context, Task<T>> action)
{
    using (var transaction = new TransactionScope())
    {
        //do some async logic before action
        var result = await action(context).ConfigureAwait(false);
        //do other async validation logic after action
        return result;
    }
}

await vs return Task await与返回Task

The difference between:和...之间的不同:

await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
await ActionAsync(context, x => IsOddAsync(x));

In some cases you don't need the await (and also not the async of course)在某些情况下,您不需要await (当然也不需要async

Methods that perform asynchronous operations don't need to use await if:在以下情况下,执行异步操作的方法不需要使用 await:

  • There is only one asynchronous call inside the method方法内部只有一个异步调用
  • The asynchronous call is at the end of the method异步调用在方法的最后
  • Catching/handling exception that may happen within the Task is not necessary不需要捕获/处理任务中可能发生的异常

See Returning a Task without await .请参阅在没有等待的情况下返回任务

In that case you could return the Task intermediately.在这种情况下,您可以中间返回Task

Please note there is a small difference in behavior - depending on the implementation of IsOddAsync :请注意,行为存在细微差别 - 取决于IsOddAsync的实现:

Important: Returning the Task instead of awaiting it, changes the exception behavior of the method, as it won't throw the exception inside the method which starts the task but in the method which awaits it.重要提示:返回任务而不是等待它,会改变方法的异常行为,因为它不会在启动任务的方法中抛出异常,而是在等待它的方法中抛出异常。

As Gabriel Luci noted, with the current implementation of IsOddAsync (one call and an await ), there is no difference in behavior.正如 Gabriel Luci 所指出的,使用IsOddAsync的当前实现(一个调用和一个await ),行为没有区别。

x => IsOddAsync(x) vs IsOddAsync x => IsOddAsync(x)IsOddAsync

The difference between和...之间的不同

await ActionAsync(context, x => IsOddAsync(x));
await ActionAsync(context, IsOddAsync);

In the first one your are creating an anonymous (lambda) method with the parameter x .在第一个中,您正在创建一个带有参数x的匿名(lambda)方法。 As IsOddAsync has also one parameter (with the same type), there is no need for the lambda method.由于IsOddAsync也有一个参数(类型相同),因此不需要 lambda 方法。

Please note you need the lambda if IsOddAsync has other parameters, eg and 2nd parameter, then you need the lambda.请注意您需要 lambda 如果IsOddAsync有其他参数,例如和第二个参数,那么您需要 lambda。 Example:例子:

await ActionAsync(context, x => IsOddAsync(x, "mySecondParameter"));

In this case there is no difference in behavior, except the callstack when an exception in thrown inside.在这种情况下,行为没有区别,除了调用堆栈中抛出异常时。

I'm trying to decide which one to use in my codebase and based on my knowledge all 3 behave the same.我正在尝试决定在我的代码库中使用哪一个,并且根据我的知识,所有 3 个行为都相同。

In this specific instance, this is essentially true.在这个特定的例子中,这基本上是正确的。

This one creates a delegate that refers to the IsOddAsync method:这个创建了一个引用IsOddAsync方法的委托:

await ActionAsync(context, IsOddAsync);

This one creates a method for the lambda expression and the delegate refers to that compiler-generated method:这为 lambda 表达式创建了一个方法,并且委托引用了该编译器生成的方法:

await ActionAsync(context, x => IsOddAsync(x));

And this one does the same, but for an asynchronous lambda, so the compiler-generated method also has an async state machine:和这个一样,但是对于一个异步 lambda,所以编译器生成的方法也有一个async state 机器:

await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));

In general, your question boils down to two questions:一般来说,您的问题归结为两个问题:

  1. Should I use method groups instead of lambdas?我应该使用方法组而不是 lambdas 吗? Yes, you should.是的你应该。 There's no disadvantage to doing so, and it's a tiny bit more efficient, shorter code, without any impact on maintainability.这样做没有缺点,而且它的效率更高,代码更短,对可维护性没有任何影响。
  2. Should I elide async / await or keep the keywords in?我应该省略async / await还是保留关键字? This one is more nuanced.这个比较细致。

Eliding async in this particular case is fine, because all the async lambda is doing is calling a single method and passing its parameter.在这种特殊情况下删除async很好,因为 lambda 所做的所有async操作都是调用单个方法并传递其参数。 There's no possibility of exceptions being thrown from the lambda before or after the call to IsOddAsync .在调用IsOddAsync之前或之后,不可能从 lambda 引发异常。

However, if your lambda is more complex - doing operations on x before passing it to IsOddAsync , or doing operations on the result, or using a using block, then you'd want to keep the async / await keywords for maximum maintainability.但是,如果您的 lambda 更复杂 - 在将x传递给IsOddAsync之前对其进行操作,或者对结果进行操作,或者使用using块,那么您需要保留async / await关键字以获得最大的可维护性。 More information here .更多信息在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM