如何准确地确定是否通过异步方法调用方法

时间:2016-11-16 23:29:20

标签: c# .net reflection async-await .net-4.6

我正在尝试确定某个方法是否由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(如果我正确地阅读它)似乎暗示我当前的解决方案(请参阅下面的代码示例)是正确的,但它并不是真正的权威"来源,此时约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,那么我总是从堆栈跟踪中获取MoveNext吗?此外,是否有人知道微软是否在某处提供文件(如果我要求证明我的解决方案能够正常运行)?

编辑:此处的主要用途是记录调用记录器的方法的名称和参数。如果来电者异步,那么我知道以下代码

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)

显然,效率较低。理论上,我可以为每个记录器调用执行此操作,但这会有点性能损失,如果可能的话,我宁愿避免这种情况。

1 个答案:

答案 0 :(得分:2)

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