TaskScheduler.FromCurrentSynchronizationContext() in .NET

本文关键字:in NET FromCurrentSynchronizationContext TaskScheduler | 更新日期: 2023-09-27 18:15:06

我得到一个运行时异常试图运行下面的例子。

Unhandled Exception: System.InvalidOperationException: The current SynchronizationContext may not be used as a TaskScheduler.
   at System.Threading.Tasks.SynchronizationContextTaskScheduler..ctor()
   at System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext()
   at TaskDemo.MyForm..ctor() in D:'myStudio'ASPNet'CSharp'CSharp4'MyApp'MyApp'Hello.cs:line 428
   at TaskDemo.SynchronizationContextTaskScheduler() in D:'myStudio'ASPNet'CSharp'CSharp4'MyApp'MyApp'Hello.cs:line 396
   at TaskDemo.Go() in D:'myStudio'ASPNet'CSharp'CSharp4'MyApp'CLRviaCSharp'Hello.cs:line 214
   at ComputeOps.Main() in D:'myStudio'ASPNet'CSharp'CSharp4'MyApp'CLRviaCSharp'Hello.cs:line 23

代码示例:

public class TaskSchedulerTest {
    public void Test() {
        SynchronizationContextTaskScheduler();
    }
    private void SynchronizationContextTaskScheduler() {
        var f = new MyForm();
        System.Windows.Forms.Application.Run();
    }
    private sealed class MyForm : System.Windows.Forms.Form {
        public MyForm() {
            Text = "Synchronization Context Task Scheduler Demo";
            Visible = true; Width = 400; Height = 100;
        }
        private readonly TaskScheduler m_syncContextTaskScheduler =
           TaskScheduler.FromCurrentSynchronizationContext();
        private CancellationTokenSource m_cts;
        protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e) {
            if (m_cts != null) {    // An operation is in flight, cancel it
                m_cts.Cancel();
                m_cts = null;
            } else {                // An operation is not in flight, start it
                Text = "Operation running";
                m_cts = new CancellationTokenSource();
                // This task uses the default task scheduler and executes on a thread pool thread
                var t = new Task<Int32>(() => Sum(m_cts.Token, 20000), m_cts.Token);
                t.Start();
                // These tasks use the synchronization context task scheduler and execute on the GUI thread
                t.ContinueWith(task => Text = "Result: " + task.Result,
                   CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion,
                   m_syncContextTaskScheduler);
                t.ContinueWith(task => Text = "Operation canceled",
                   CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled,
                   m_syncContextTaskScheduler);
                t.ContinueWith(task => Text = "Operation faulted",
                   CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted,
                   m_syncContextTaskScheduler);
            }
            base.OnMouseClick(e);
        }
    }
}

任何想法?

TaskScheduler.FromCurrentSynchronizationContext() in .NET

将创建的m_syncContextTaskScheduler放入表单构造函数中。

public MyForm() {
    Text = "Synchronization Context Task Scheduler Demo";
    Visible = true; Width = 400; Height = 100;
    m_syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
}

谢谢!它起作用了,背后的原因是什么?

因为构造函数过早初始化了具有初始化式的只读成员。如果需要,Form类构造函数会安装同步提供程序,即一个名为WindowsFormsSynchronizationContext的类的实例。c#编译器在调用基类构造函数之前为只读初始化式生成代码。将赋值移到构造函数体中,确保它在调用基构造函数之后初始化。

注意readonly成员初始化式,保持简单。