如何准确判断一个方法是否被异步方法调用
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 中结束。
我正在尝试确定某个特定方法是否被 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 中结束。