Получить имя текущего метода из async-функции?
Есть ли способ получить имя текущего метода внутри функции async?
Я пробовал:
System.Reflection.MethodInfo.GetCurrentMethod();
И я попытался использовать StackTrace и StrackFrame следующим образом:
StackTrace strackTrace = new StackTrace();
for (int i = 0; i < strackTrace.GetFrames().Length; i++)
{
SafeNativeMethods.EtwTraceInfo("Function" + i + ":" + function);
SafeNativeMethods.EtwTraceInfo("Type" + i + ":" + strackTrace.GetFrame(i).GetType().Name);
SafeNativeMethods.EtwTraceInfo("Method" + i + ":" + strackTrace.GetFrame(i).GetMethod().Name);
SafeNativeMethods.EtwTraceInfo("ToString Call" + i + ":" + strackTrace.GetFrame(i).ToString());
}
Но ни один из них не работает, я получаю ".ctor", "InvokeMethod", "Invoke", "CreateInstance", "CreateKnownObject" или "CreateUnknownObject" или "MoveNext"
Любые идеи о том, как я могу это сделать? Я хочу создать общую функцию журнала, и я не хочу передавать имя функции, которая вызвала функцию журнала, поэтому я попробовал метод stacktrace, не работал.
Я отказался от этого и сказал: "Хорошо, я передам имя функции в качестве первого параметра, но когда я вызвал метод отражения от вызывающей функции, вызывающей общую функцию регистрации, я всегда получаю".ctor "
Любые идеи? Обратите внимание, что общая функция logger, которую я вызываю, является статическим методом в том же классе (это должно быть так на данный момент...).
Ответы
Ответ 1
С# 5 добавлены атрибуты информации о вызывающем абоненте, которые могут дать вам больше того, что вы ищете. Обратите внимание, что они вставляют соответствующую информацию в сайт вызова во время компиляции, а не используют информацию о времени выполнения. Функциональность более ограничена (вы не можете получить полный стек вызовов, очевидно), но это намного быстрее.
Пример использования CallerMemberNameAttribute:
using System.Runtime.CompilerServices;
public static void Main(string[] args)
{
Test().Wait();
}
private static async Task Test()
{
await Task.Yield();
Log();
await Task.Yield();
}
private static void Log([CallerMemberName]string name = "")
{
Console.WriteLine("Log: {0}", name);
}
Существуют также атрибуты CallerFilePath и CallerLineNumber, которые могут получать другие фрагменты информации о сайте вызова.
Ответ 2
Вместо того, чтобы делать ручные кадровые переходы, которые являются дорогостоящими и рискованными (поскольку версии Release могут оптимизировать некоторые методы), вы можете использовать CallerMemberNameAttribute
, один из атрибутов Caller Information, который был добавлен в .NET 4.5 (который вы уже используете, если вы используете async/wait ) для этого точного сценария - передача имени члена для регистраторов, обработчиков свойств и т.п.
Это происходит следующим образом:
public void LogMessage(string message, [CallerMemberName] string caller = "")
{
// caller should contain the name of the method that called LogMessage.
}
Я не знаю никаких ограничений, которые имеют методы async
.
Ответ 3
Этот метод работает от вызова метода async, а также от обычного метода.
(С# 5)
/// <summary>
/// Returns Current method name
/// </summary>
/// <returns>callers method name</returns>
public string GetCurrentMethod([CallerMemberName] string callerName = "")
{
return callerName;
}
Ответ 4
Вам нужно записать имя метода в начале метода async, где-то перед первым асинхронным вызовом. Наиболее удобным способом, который я обнаружил, чтобы пропустить мимо созданного компилятором конечного автомата, является просмотр типа объявления каждого метода в трассировке стека.
var method = new StackTrace()
.GetFrames()
.Select(frame => frame.GetMethod())
.FirstOrDefault(item => item.DeclaringType == GetType());
await Task.Yield();
if (method != null)
{
Console.WriteLine(method.Name);
}
Ответ 5
Немного поздно ответить на ваш вопрос, я думаю, но так как у меня была такая же проблема, и мне нужно было разобраться в этом из-за отсутствия хорошего разрешения на это в Интернете, вот что я сделал, и это работает отлично, по крайней мере для меня -
- Определите следующее
Regex
где-нибудь, к которому могут обращаться все вызывающие, поскольку Regex
объекты должны быть проанализированы перед их использованием; следовательно, это может быть дорогостоящим, и это не очень хорошая практика, чтобы создавать их снова и снова, если мы можем использовать один и тот же.
public static readonly Regex ASYNC_METHOD_NAME_FORMAT = new Regex(@"^\<(?\w+)>\w+?");
- Используйте следующий код, чтобы получить имя метода
string methodName = ASYNC_METHOD_NAME_FORMAT.Match(MethodBase.GetCurrentMethod().ReflectedType.Name).Groups["method_name"].Value
Надеюсь, это поможет!
Ответ 6
Вы можете отправить strackTrace.GetFrame(i).GetMethod(), который является объектом System.Reflection.MethodBase для функции, которая проверяет, имеет ли System.Reflection.MethodBase.DeclaringType.FullName символы < > и если так получится имя запрошенного метода, которое лежит между символами <... > .
static private string getMethodName(System.Reflection.MethodBase method)
{
string _methodName = method.DeclaringType.FullName;
if (_methodName.Contains(">") || _methodName.Contains("<"))
{
_methodName = _methodName.Split('<', '>')[1];
}
else
{
_methodName = method.Name;
}
return _methodName;
}
И пример использования:
var _stackTrace = new System.Diagnostics.StackTrace(exception, true);
string _methodName = getMethodName(_stackTrace.GetFrame(0).GetMethod());
Ответ 7
Я использовал смесь ответов Натана и Майка.
Использование GetType()
для запроса метода из трассировки стека не работает для меня. Не гарантировано. Но использование CallerMemberNameAttrinute
позволяет мне получить точный метод по его имени.
Так что мой код будет:
using System.Runtime.CompilerServices;
public static void Main(string[] args)
{
Test().Wait();
}
private static async Task Test()
{
await Task.Yield();
Log();
await Task.Yield();
}
private static void Log([CallerMemberName]string methodName = "")
{
var method = new StackTrace()
.GetFrames()
.Select(frame => frame.GetMethod())
.FirstOrDefault(item => item.Name == methodName);
Console.WriteLine("Log: {0}", method.DeclaringType + "." + method.Name);
}
Таким образом, я получаю имя метода с полным путем к пространству имен.