2012-03-24 3 views
4

HINWEIS: Ich sage nicht, dass dies eine gute Idee ist, nur um herauszufinden, ob es eine "bessere" Option als diese Brute-Force-Option gibt.bessere Optionen als das manuelle Wörterbuch für die Referenzierung der 'aktuellen Aufgabe', in der eine Methode ausgeführt wird?

Dies kam in einem früheren SO gewinde @How to get the current task reference?

jedoch, dass Faden durch eine bestimmte Schnittstelle ein wenig eingeschränkt war.

Die Brute-Force-Ansatz, den ich zusammengeworfen schnell verwendet nur ein Wörterbuch der schwachen Referenzen.

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); 
      } 
     } 
    } 
} 

Dies bedeutet aber klar, was die Aufgaben schafft gezwungen ist, mit diesen zusätzlichen Kopfschmerzen zu behandeln, so ist es nicht sehr brauchbar, insbesondere WRT C# 5 Asynchron-Verfahren, bei denen die Aufgabe nicht so explizit erstellt.

Auch hier ist es wahrscheinlich eine schlechte Idee, einen Code zu haben, der dies benötigt, also denken Sie eher an eine Gedankenübung. :)

+0

Wenn Sie nicht sicher sind, ob das eine gute Idee ist, warum versuchen Sie es dann? – svick

+0

Auch, ich denke, Sie können es nicht C# 5 async-freundlich machen, weil 'Task.CurrentId' innerhalb einer asynchronen Methode' null' zurückgibt. – svick

+0

@svick - faszinierend - Ich hätte nicht erwartet, dass CurrentId in einer asynchronen Methode null ist (naja, nach der ersten Wartezeit). Pass auf zu wissen, warum das so ist? –

Antwort

0

Es gibt leider keinen besseren Weg, und da das letztendliche Ziel war, Task.CurrentId abzuschalten, ist es in der Tat nicht einmal nützlich, da wir keine 'aktuelle Aufgaben-ID' bekommen können. für asynchrone Methoden (nach dem ersten Warten, so dass es bereits zum Aufrufer zurückgekehrt ist).

Verwandte Themen