2012-08-23 113 views
3

我期待從C#中的任務獲取方法/操作名稱。具體來說,我正在實現一個自定義任務調度程序,並且希望生成任務運行持續時間的統計信息,然後我將通過任務內運行的方法進行聚合。在visual studio調試器中,您可以訪問它並查看m_action私有變量以及調試器顯示註釋,並將其顯示爲Method = {0}。有沒有什麼辦法可以從任務本身訪問它?獲取任務的方法名稱

+4

問題是,這將是多麼有用。您(通常)傳遞給「Task」的lambda表達式由C#編譯器轉換爲方法,並獲取由編譯器生成的名稱。這些名稱不是[非常有說服力](http://stackoverflow.com/q/10450311/21567),並且很難將它們與實際代碼重新關聯。 –

+0

@ Christian.K如果只限於非常簡單的lambda表達式,那麼可以使用'Expression'而不是委託並從中獲取方法名稱。 (當然,'Expression'可以調用幾種方法,所以你必須以某種方式選擇顯示哪一種,並且它也可能不會調用任何方法。) – svick

回答

2

嗯,你可以使用反射來獲取在私人m_action領域,賦予了Task變量task

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

然後獲得該方法的Name和​​:

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

爲了得到完全限定的方法(type + "." + name)...

但是,只要執行任務的完成,m_actionnull。我不知道這將適用於TaskFactory.StartNew ...

0
  1. 嘗試反射以獲取m_action變量。
  2. 嘗試從Envorinment.StackTrace或從任務內部直接調用方法獲取信息。
3

您可以從任務繼承,使這個真正的輕鬆......我只是要在這裏實現第一個構造函數的例子:

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" 
+0

有趣的想法。除了:1.'MethodInfo.ToString()'不返回方法,名稱,它返回整個簽名。例如。像'Void AsyncMethod()'。要獲取名稱,請使用Name屬性。 2.正如Christian在評論中指出的那樣,這不會給lambdas帶來有用的結果。 – svick

+0

好點。對於#1,如果您確實只需要方法名稱,則可以將其從簽名中解析出來。對於#2,在我的例子中,我使用了一個lambda ...所以我想也許你的意思是它不會給匿名方法有用嗎?在這種情況下,它仍將返回一個方法名稱 - 它只是編譯器爲匿名方法生成的方法名稱。在這裏,您可以創建另一個構造函數,允許您在創建任務時爲匿名方法指定自己的名稱。 – James

+0

就像我說的,你可以使用'Name'屬性,不需要解析任何東西。 – svick