【问题标题】:Async version of a method wrapper方法包装器的异步版本
【发布时间】:2020-01-28 02:21:12
【问题描述】:

我有几个由 API 提供给我的方法。我希望编写一个方便的助手来记录所述方法的执行时间,以及一般的任何代码块。

用例方法通常如下所示:

object       GetData(string statementKey, string parametersJson, out string errorMessage);
Task<object> GetDataAsync(string statementKey, string parametersJson, CancellationToken cancellationToken = default(CancellationToken));

我为同步方法写了一个方法包装器:

public static T With<T>(string message, Func<T> func)
{
    var watch = new Stopwatch();

    T returned;

    watch.Start();
    try
    {
        returned = func.Invoke();
    }
    catch (Exception exception)
    {
        Log.Logger.Error(exception, $"Error in {message}");
        throw;
    }
    finally
    {
        watch.Stop();
    }

    // Logging logic here

    return returned;
}

(我知道这不适用于 void 方法,但如果操作是同步的,则操作重载是微不足道的)。

现在如果传递的方法是异步的,我会测量不准确的执行时间。我对如何更改上述方法以使用异步方法感到有些困惑。

我试过这个实现,但感觉不对。

public static async Task<T> AsyncWith<T>(string message, Func<Task<T>> func)
{
    T returned;


    try
    {
        var watch = new Stopwatch();
        watch.Start();
        returned = await func.Invoke().ConfigureAwait(false);
        watch.Stop();
        // Logging logic here
    }
    catch (Exception exception)
    {
        Log.Logger.Error(exception, $"Error in {message}");
        throw;
    }

    return returned;
}

我真的不应该开始一个任务吗?我不明白为什么它使用T returned 而不是Task&lt;T&gt; returned 进行编译

【问题讨论】:

  • Shouldn't I start a task actually ? - 任务应该由func 启动。从技术上讲,func 可能会返回一个尚未开始的任务,但这会奇怪I don't understand why it is compiling with T returned instead of Task&lt;T&gt; returned - 因为您已将 AsyncWith 标记为 async。在标记为async 的方法中,您return 是在Task&lt;T&gt; 中声明的类型。
  • 你是otherwise fine
  • 什么意思 - 时间不准确?当来自 func 的任务完成时,等待任务将运行 watch.Stop() - 这意味着它将测量 func 的正确执行时间。
  • @vasiloreshenski 如果我将上面编写的 With 方法与异步委托一起使用,finally 块可能会在异步委托调用完成之前执行,我不会测量执行时间异步方法。因此需要一个异步方法。
  • @FooBar 在底层,编译器将异步方法转换为状态机like this

标签: c# .net async-await


【解决方案1】:

我试过这个实现,但感觉不对。

你的实现是正确的。

我真的不应该开始一个任务吗?

方法返回它们的“热”任务——即运行。所以调用func.Invoke() 就足够启动任务了。

我不明白为什么编译时返回的是 T 而不是 Task 返回

因为async 关键字为您处理创建Task&lt;T&gt; 包装器,并将return 语句(或异常)转换为完成Task&lt;T&gt; 的逻辑。

【讨论】:

  • 谢谢。我有一个后续问题。看我写的方法,对于async版本的void With(string message, Action action),我有两种方法。传递的方法是async Task,我可以写签名async Task AsyncWith&lt;T&gt;(string message, Func&lt;Task&gt; func),或者方法是可怕的async void。出于好奇,你会建议我如何处理这些问题?我相信它应该类似于async Task AsyncWith(string message, Action action),只是忘记代表:await Task.Run(action.Invoke).ConfigureAwait(false)。这是正确的方法吗?
  • The async version of Action is Func&lt;Task&gt;,所以使用async Task AsyncWith(string message, Func&lt;Task&gt; func)await func().ConfigureAwait(false);。不需要Task.Run
猜你喜欢
  • 2014-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多