如何通过 TaskCompletionSource 将任务状态设置为 "Running"

How can I set the state of a task to "Running" via TaskCompletionSource

在我的程序中的某些情况下,我使用 TaskCompletionSource 创建任务并操纵其状态。
在其他情况下,任务以“常规”方式创建和执行。

在常规任务创建和执行的情况下,任务在执行时的状态为“运行”。这个“运行”状态在其他地方被检查以确保任务正在执行?

如何在使用 TaskCompletionSource 时在任务上设置此状态?如果我不将状态设置为“运行”,则上述检查将失败。

我发现实现这一目标的唯一方法是通过反射。以下解决方案已经过测试并且有效。

private const string s_fieldName_StateFlags = "m_stateFlags";

/// <summary> From https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs </summary>
[Flags]
public enum TaskState
{
  TASK_STATE_STARTED                      = 0x10000,    //bin: 0000 0000 0000 0001 0000 0000 0000 0000
  TASK_STATE_DELEGATE_INVOKED             = 0x20000,    //bin: 0000 0000 0000 0010 0000 0000 0000 0000
  TASK_STATE_DISPOSED                     = 0x40000,    //bin: 0000 0000 0000 0100 0000 0000 0000 0000
  TASK_STATE_EXCEPTIONOBSERVEDBYPARENT    = 0x80000,    //bin: 0000 0000 0000 1000 0000 0000 0000 0000
  TASK_STATE_CANCELLATIONACKNOWLEDGED     = 0x100000,   //bin: 0000 0000 0001 0000 0000 0000 0000 0000
  TASK_STATE_FAULTED                      = 0x200000,   //bin: 0000 0000 0010 0000 0000 0000 0000 0000
  TASK_STATE_CANCELED                     = 0x400000,   //bin: 0000 0000 0100 0000 0000 0000 0000 0000
  TASK_STATE_WAITING_ON_CHILDREN          = 0x800000,   //bin: 0000 0000 1000 0000 0000 0000 0000 0000
  TASK_STATE_RAN_TO_COMPLETION            = 0x1000000,  //bin: 0000 0001 0000 0000 0000 0000 0000 0000
  TASK_STATE_WAITINGFORACTIVATION         = 0x2000000,  //bin: 0000 0010 0000 0000 0000 0000 0000 0000
  TASK_STATE_COMPLETION_RESERVED          = 0x4000000,  //bin: 0000 0100 0000 0000 0000 0000 0000 0000
  TASK_STATE_THREAD_WAS_ABORTED           = 0x8000000,  //bin: 0000 1000 0000 0000 0000 0000 0000 0000
  TASK_STATE_WAIT_COMPLETION_NOTIFICATION = 0x10000000, //bin: 0001 0000 0000 0000 0000 0000 0000 0000
  TASK_STATE_EXECUTIONCONTEXT_IS_NULL     = 0x20000000, //bin: 0010 0000 0000 0000 0000 0000 0000 0000
  TASK_STATE_TASKSCHEDULED_WAS_FIRED      = 0x40000000, //bin: 0100 0000 0000 0000 0000 0000 0000 0000
}

public  static void SetTaskRunning<TResult> (TaskCompletionSource<TResult> i_taskCompletionSource)
{
  if (i_taskCompletionSource == null)
    throw new ArgumentNullException (nameof (i_taskCompletionSource));

  var value = TaskState.TASK_STATE_STARTED
           |  TaskState.TASK_STATE_DELEGATE_INVOKED;

  var task      = i_taskCompletionSource.Task;
  var type      = task.GetType ();
  var fieldInfo = type.GetField (s_fieldName_StateFlags, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
  fieldInfo.SetValue (task, (int)value);
}