2011-11-19 52 views
6

我得到一個運行時異常,試圖運行下面的示例。.NET中的TaskScheduler.FromCurrentSynchronizationContext()

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

任何想法?

回答

7

將創建m_syncContextTaskScheduler放入您的窗體構造函數。

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

謝謝!它的工作原理是什麼?背後的原因是什麼? – Pingpong

+3

因爲'FromCurrentSynchronizationContext()'在變量初始化期間不在有效的上下文中(需要在UI線程中)。哦,請接受答案,它鼓勵人們幫助你:) – Alex

6

謝謝!它的工作原理是什麼?背後的原因是什麼?

因爲構造函數初始化只讀有一個初始化過早的成員。 Form類構造函數根據需要安裝同步提供程序,該類是名爲WindowsFormsSynchronizationContext的類的實例。 C#編譯器在調用基類構造函數之前生成只讀初始化程序的代碼。將賦值移動到構造函數主體中可確保在調用基礎構造函數後對其進行初始化

小心只讀成員初始值設定項,使它們簡單。

+0

感謝您的解釋。 – Pingpong

相關問題