比手动字典更好的选项用于引用';当前任务';一个方法正在内部运行

本文关键字:一个 方法 运行 在内部 当前任务 选项 更好 用于 引用 字典 | 更新日期: 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"(在第一次等待之后,所以它已经返回给调用方了)。