Получение имени метода задачи


Я ищу, чтобы получить имя метода / действия из задачи в C#. В частности, я реализую пользовательский планировщик задач и хотел бы генерировать статистику о продолжительности выполнения задачи, которую я затем агрегирую методом, запущенным внутри задачи. В отладчике visual studio вы можете получить к нему доступ и увидеть закрытую переменную m_action, а также аннотацию отображения отладчика, отображающую ее как Method={0}. Есть ли способ получить доступ к этому из самой задачи?

3 3

3 ответа:

Ну, вы можете использовать отражение, чтобы добраться до частного поля m_action, заданного переменной Task task:

    var fieldInfo = typeof(Task).GetField("m_action", BindingFlags.Instance | BindingFlags.NonPublic);
    Delegate action = fieldInfo.GetValue(task) as Delegate;

Затем получаем Name метода и DeclaringType:

    var name = action.Method.Name;
    var type = action.Method.DeclaringType.FullName;

, чтобы получить полностью квалифицированный метод (type + "." + name)...

Но, как только задача выполняется до завершения, m_action является null. Я не уверен, как это будет применяться с TaskFactory.Начать заново...

Вы можете наследовать от задачи, чтобы сделать это очень легко... Я просто собираюсь реализовать первый конструктор здесь для примера:

public class NamedTask : Task {
    public string MethodName { get; set; }
    public NamedTask(Action action) : base(action) {
        MethodName = action.Method.Name;
    }
    public NamedTask(Action action, CancellationToken cancellationToken) : base(action, cancellationToken) {}
    public NamedTask(Action action, TaskCreationOptions creationOptions) : base(action, creationOptions) {}
    public NamedTask(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions) : base(action, cancellationToken, creationOptions) {}
    public NamedTask(Action<object> action, object state) : base(action, state) {}
    public NamedTask(Action<object> action, object state, CancellationToken cancellationToken) : base(action, state, cancellationToken) {}
    public NamedTask(Action<object> action, object state, TaskCreationOptions creationOptions) : base(action, state, creationOptions) {}
    public NamedTask(Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions) : base(action, state, cancellationToken, creationOptions) {}
}

После этого...

NamedTask task = new NamedTask(() => AsyncMethod(arg1, arg2, argN));
string methodName = task.MethodName; // there's the name!

Еще примеры. Наследовать от Task<T>:

public class NamedTask<T> : Task<T> {
    public string MethodName { get; set; }
    public NamedTask(Func<T> function) : base(function) {
        MethodName = function.Method.Name;
    }
    public NamedTask(Func<T> function, string methodName) : base(function) {
        MethodName = methodName;
    }
    ...
}

Обрабатывать анонимные методы:

NamedTask<bool> task2 = new NamedTask<bool>(() => {
                // some arbitrary code
                return true;
    });

NamedTask<bool> task3 = new NamedTask<bool>(() => {
                // some arbitrary code
                return true;
    }, "ReturnTrueMethod");

string methodName2 = task2.MethodName; // returns "<LongRunning_Async>b__19"
string methodName3 = task3.MethodName; // returns "ReturnTrueMethod"
  1. Попробуйте reflection получить переменную m_action.
  2. попробуйте получить информацию из Envorinment.StackTrace изнутри задачи или непосредственно вызываемых ею методов.