如何准确判断一个方法是否被异步方法调用

How to accurately determine whether a method was called by an async method

我正在尝试确定某个特定方法是否被 async 方法调用。

This answer(当然,这描述了一些不同的情况)建议使用 CallerMemberName 属性来查找调用方法的名称。实际上,我的方法的签名如下所示:

public void LogCallAsync([CallerMemberName] string caller = "", params object[] parameters)

如果你正在做类似

的事情,它会很好用
logger.LogCallAsync();

如果你有固定数量的参数,它也会很好用。但是,假设下一个参数是 params object[] 类型,显然情况并非如此,因此如果您尝试执行类似

的操作
logger.LogCallAsync(someObject, someOtherObject)

我会得到一个编译异常,因为 someObject 不是一个字符串。我尝试了以下解决方法:

logger.LogCallAsync(nameof(CurrentMethod), someObject, someOtherObject);

这很丑。实际上,如果我 不需要 必须这样做,我会更喜欢它,所以如果有人在这方面有任何建议那会很棒,但关于我的主要问题:有没有某种防止人们不恰当地称呼它的方法?特别是,我想知道 "CurrentMethod" 是否是 ,实际上是一个实际的 async 方法。

例如,如果我查看 StackTrace 的实例,是否有可靠的判断方法? This article(如果我没看错的话)似乎暗示我当前的解决方案(请参阅下面的代码示例)是正确的,但它并不是真正的 "authoritative" 来源,而且它已有 5 年历史了点.

让我展示一个代码示例来说明我现在是如何尝试解决这个问题的:

private static void GetCaller()
    {
        StackTrace stack = new StackTrace();
        MethodBase method = stack.GetFrame(1).GetMethod();

        Trace.TraceInformation("Method name: " + method.Name);
    }

    // Some arbitrary async method
    private static async Task UseReflection()
    {
        // Do some kind of work
        await Task.Delay(100);

        // Figure out who called this method in the first place
        // I want some way of figuring out that the UseReflection method is async
        GetCaller();
    }

    static void Main(string[] args)
    {
        // AsyncPump is basically to make Async work more like it does on a UI application
        // See this link: https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/
        AsyncPump.Run(async () =>
        {
            // In this case, it identifies the calling method as "MoveNext"
            // Question: in cases like this, will this always be the case (i.e. will it always be MoveNext)?
            await UseReflection();
        });

        // In this case, it identifies the calling method as "Main"
        GetCaller();
    }

我使用的是 Visual Studio 2015 和 .NET 4.6,物有所值。那么,我的问题是:我能否保证代码将始终以类似于我上面的方式工作?例如,如果 GetCaller 被异步方法调用,我会 always 从堆栈跟踪中获取 MoveNext 吗?另外,有谁知道 Microsoft 是否在某处记录了这一点(以防我被要求证明我的解决方案有效)?

编辑: 这里的主要目的是记录调用记录器的方法的名称和参数。如果调用者是不是异步的,那我就知道下面的代码

StackTrace stack = new StackTrace();
MethodBase method = stack.GetFrame(1).GetMethod();

会告诉我来电者是谁。但是,如果调用者是 async,那显然根本行不通。在那种情况下,我目前执行以下操作:

StackTrace st = new StackTrace();
StackFrame callFrame = st.GetFrames().ToList().FirstOrDefault(x => x.GetMethod().Name == caller);

其中 caller 是我传递的方法调用的名称,就像我在上面列出的签名中一样:

public void LogCallAsync([CallerMemberName] string caller = "", params object[] parameters)

显然,这样效率较低。从理论上讲,我可以对每个记录器调用都这样做,但这会对性能造成一点影响,我宁愿尽可能避免这种情况。

是的,所有异步方法都在 MoveNext 中结束。