【问题标题】:Getting the method name of a task获取任务的方法名
【发布时间】:2012-08-24 03:25:46
【问题描述】:

我希望从 C# 中的任务中获取方法/操作名称。具体来说,我正在实现一个自定义任务调度程序,并希望生成有关任务运行持续时间的统计信息,然后我将通过任务内部运行的方法对其进行汇总。在 Visual Studio 调试器中,您可以访问它并查看 m_action 私有变量以及调试器显示注释,将其显示为 Method={0}。有什么方法可以从任务本身访问它?

【问题讨论】:

  • 问题是,这会有多大用处。您(通常)传递给 Task 的 lambda 表达式被 C# 编译器转换为方法并获得编译器生成的名称。这些名称不是very telling,很难将它们与实际代码重新关联。
  • @Christian.K 如果可以将自己限制在非常简单的 lambda 表达式中,您可以使用 Expression 而不是委托并从中获取方法名称。 (当然,Expression 可以调用多种方法,因此您必须以某种方式选择要显示的方法。而且它也可能不会调用任何方法。)

标签: c# task task-parallel-library


【解决方案1】:

您可以从 Task 继承以使这变得非常简单...我将在这里实现第一个构造函数作为示例:

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&lt;T&gt;

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. MethodInfo.ToString() 不只返回方法名称,它返回整个签名。例如。类似Void AsyncMethod()。要仅获取名称,请使用 Name 属性。 2. 正如 Christian 在评论中指出的那样,这不会为 lambdas 提供有用的结果。
  • 好点。对于 #1,如果您真的只想要方法名称,您可以将其从签名中解析出来。对于#2,在我的示例中,我使用了 lambda ...所以我想您的意思是它不会为匿名方法提供任何有用的信息?在这种情况下,它仍然会返回一个方法名——它只是编译器为匿名方法生成的方法名。在这里,您可以创建另一个构造函数,允许您在创建任务时为匿名方法指定自己的名称。
  • 就像我说的,你可以使用Name属性,不需要解析任何东西。
  • 啊,action.Method.Name。是的!好东西。我将更改帖子以反映这一点。
【解决方案2】:

好吧,你可以使用反射来获取私有的m_action 字段,给定一个Task 变量task

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

然后获取方法的NameDeclaringType

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

要获得完全限定的方法(type + "." + name)...

但是,一旦任务执行完成,m_action 就是null。我不确定这将如何应用于 TaskFactory.StartNew...

【讨论】:

    【解决方案3】:
    1. 尝试反射以获取 m_action 变量。
    2. 尝试从任务内部的Envorinment.StackTrace 获取信息或直接由它调用方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-12
      • 2021-01-02
      相关资源
      最近更新 更多