在不等待的情况下使用带有异步任务的语句

using statement with asynchronous Task inside not await

  1. 我创建了一个 IDisposable 对象来记录 Dispose 的执行时间。

  2. 然后,我创建了一个RealProxy,它使用这个对象来记录我业务的任何方法调用的时间class

  3. 我的业务class使用异步方法,然后在任务完成之前留下using语句,然后记录错误的执行时间。

这是我的代码:

/// <summary>
///  Logging proxy with stopwatch
/// </summary>
/// <typeparam name="T"></typeparam>
public sealed class LoggingProxy<T> : RealProxy// where T : MarshalByRefObject
{
    private ILog _logger;
    private readonly T _instance;

    private LoggingProxy(T instance, ILog logger)
        : base(typeof(T))
    {
        _logger = logger;
        _instance = instance;
    }

    /// <summary>
    /// Create the Transparent proy for T
    /// </summary>
    /// <param name="type">An implementation type of T</param>
    /// <returns>T instance</returns>
    public static T Create(ILog logger)
    {
            logger.DebugFormat("[{0}] Instantiate {1}", "LoggingProxy", typeof(T).Name);
            var instance = (T)Activator.CreateInstance(typeof(T), logger);

            //return the proxy with execution timing if debug enable in logger
            if (logger.IsDebugEnabled)
                return (T)new LoggingProxy<T>(instance, logger).GetTransparentProxy();
            else
                return instance;
    }


    /// <summary>
    /// Invoke the logging method using Stopwatch to log execution time
    /// </summary>
    /// <param name="msg"></param>
    /// <returns></returns>
    public override IMessage Invoke(IMessage msg)
    {
        var methodCall = (IMethodCallMessage)msg;
        var method = (MethodInfo)methodCall.MethodBase;

        string methodName = method.Name;
        string className = method.DeclaringType.Name;

        //return directly methods inherited from Object
        if (method.DeclaringType.Name.Equals("Object"))
        {
            var result = method.Invoke(_instance, methodCall.Args);
            return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
        }

        using (var logContext = _logger.DebugTiming("[{0}] Execution time for {1}", className, methodName))
        {
            _logger.DebugFormat("[{0}] Call method {1}", className, methodName);
            //execute the method
            //var result = method.Invoke(_instance, methodCall.Args);
            object[] arg = methodCall.Args.Clone() as object[];
            var result = method.Invoke(_instance, arg);

            //wait the task ends before log the timing
            if (result is Task)
                (result as Task).Wait();

            return new ReturnMessage(result, arg, 0, methodCall.LogicalCallContext, methodCall);
        }

    }

_logger.DebugTiming 方法启动秒表并将其记录在 Dispose 上。 我发现让它与异步方法一起工作的唯一方法是使用该行:

            //wait the task ends before log the timing
            if (result is Task)
                (result as Task).Wait();

但我只是觉得这样做破坏了异步方法的所有好处。

-> 如果您对如何正确实施有建议

-> 知道调用 wait() 对代理的真正影响吗?

您可以使用 Task.ContinueWith():

public override IMessage Invoke(IMessage msg)
{
    var methodCall = (IMethodCallMessage)msg;
    var method = (MethodInfo)methodCall.MethodBase;

    string methodName = method.Name;
    string className = method.DeclaringType.Name;

    //return directly methods inherited from Object
    if (method.DeclaringType.Name.Equals("Object"))
    {
        var result = method.Invoke(_instance, methodCall.Args);
        return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
    }

    var logContext = _logger.DebugTiming("[{0}] Execution time for {1}", className, methodName);
    bool disposeLogContext = true;
    try
    {
        _logger.DebugFormat("[{0}] Call method {1}", className, methodName);
        //execute the method
        //var result = method.Invoke(_instance, methodCall.Args);
        object[] arg = methodCall.Args.Clone() as object[];
        var result = method.Invoke(_instance, arg);

        //wait the task ends before log the timing
        if (result is Task) {
            disposeLogContext = false;
            ((Task)result).ContinueWith(() => logContext.Dispose());
        }

        return new ReturnMessage(result, arg, 0, methodCall.LogicalCallContext, methodCall);
    }
    finally
    {
        if (disposeLogContext)
            logContext.Dispose();
    }
}

不要在任务上调用 Wait() - 这会改变行为并可能导致死锁。