比手动字典更好的选项用于引用';当前任务';一个方法正在内部运行
本文关键字:一个 方法 运行 在内部 当前任务 选项 更好 用于 引用 字典 | 更新日期: 2023-09-27 18:28:59
注意:我并不是说这是一个好的想法,只是想知道是否有比这个暴力的"更好"的选择。
这是在上一个SO线程中出现的@如何获得当前任务引用?
然而,该线程受特定接口的约束要大一些。
我快速拼凑出的暴力方法只使用了一本弱引用的字典。
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异步方法,因为它没有明确地创建任务。
同样,拥有需要这一点的代码可能是个坏主意,所以将其视为更类似于思考练习。:)
不幸的是,没有什么更好的方法了,因为最终目标是关闭Task.CurrentId,所以它实际上甚至没有用处,因为我们无法获得异步方法的"当前任务id"(在第一次等待之后,所以它已经返回给调用方了)。