2012-03-24 32 views
4

注:我不是說這是一個好想法,只是試圖找出是否有比這蠻力一個「好」的選擇。比手動字典更好的選項來引用方法在裏面運行的'當前任務'?

這在以前想出了SO線程@How to get the current task reference?

然而,該線程是由一個特定的接口多一點約束。

蠻力的方法,我趕緊扔在一起,只使用弱引用的字典。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 

namespace GetCurrentTaskExample 
{ 
    public static class TaskContext 
    { 
     // don't need a ConcurrentDictionary since we won't be reading/writing the same task id with different tasks concurrently 
     private static readonly Dictionary<int, WeakReference> s_indexedTaskReferences = new Dictionary<int, WeakReference>(); 

     public static void AddAndStartTasks(IEnumerable<Task> tasks) 
     { 
      foreach (var task in tasks) 
      { 
       AddTask(task); 
       task.Start(); 
      } 
     } 

     public static void AddTask(Task task) 
     { 
      s_indexedTaskReferences[task.Id] = new WeakReference(task); 
     } 

     public static Task GetCurrentTask() 
     { 
      var taskId = Task.CurrentId; 
      if (taskId == null) return null; 

      WeakReference weakReference; 
      if (s_indexedTaskReferences.TryGetValue(taskId.Value, out weakReference) == false) return null; 
      if (weakReference == null) return null; // should not happen since we don't store null as a value 

      var task = weakReference.Target as Task; 
      return task; 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var tasks = Enumerable.Range(0, 100) 
       .Select(i => new Task(VerifyCurrentTaskWorks, i)) 
       .ToArray(); 

      TaskContext.AddAndStartTasks(tasks); 

      Task.WaitAll(tasks); 
     } 

     static void VerifyCurrentTaskWorks(object instanceIdentifier) 
     { 
      var currentTask = TaskContext.GetCurrentTask(); 

      if (currentTask.Id == Task.CurrentId) 
      { 
       Console.WriteLine("Verified for instance {0} that Task.CurrentId value of {1} matches Id property {2} of task {3}", 
            instanceIdentifier, Task.CurrentId, currentTask.Id, currentTask); 
      } 
      else 
      { 
       var errorMessage = String.Format("TaskContext.GetCurrentTask() failed for instance {0} with Task.CurrentId value of {1} and currentTask.Id value of {2}", 
            instanceIdentifier, Task.CurrentId, currentTask.Id); 
       throw new InvalidOperationException(errorMessage); 
      } 
     } 
    } 
} 

然而,這顯然意味着無論是創建任務被迫處理這個額外的頭痛,所以它不是非常實用,在不那麼明確創建任務特別WRT C#5異步方法。

再次,可能是一個壞主意,有需要的代碼,所以認爲它更像是一個思想的鍛鍊。 :)

+0

如果你不知道這是一個好主意,那你爲什麼要做呢? – svick 2012-03-24 23:19:36

+0

另外,我認爲你不能使它成爲異步友好的C#5,因爲在異步方法中'Task.CurrentId'返回'null'。 – svick 2012-03-24 23:26:01

+0

@svick - 迷人的 - 我也沒有想到CurrentId是在異步方法無效(當然,第一的await後)。知道爲什麼會發生? – 2012-03-25 04:21:17

回答

0

不幸的是,沒有更好的方法,而且最終的目標是關閉Task.CurrentId,它確實沒有用,因爲我們無法獲得'當前任務ID'對於異步方法(在第一次等待之後,所以它已經返回給調用者)。

相關問題