2011-08-16 210 views
6

錯誤:Object reference not set to an instance of an object.爲什麼SynchronizationContext.Current爲空?

下面的算法工作。 我試了一下,然後我把Winform項目移到了另一個目錄,SynchronizationContext.Currentnull。 爲什麼?

SynchronizationContext uiCtx = SynchronizationContext.Current; 

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    int[] makeSelfMoves = new int[4]; 

    lock (replay) 
    { 
     // count should be more than 2 
     foreach (KeyValuePair<int, int[]> item in replay) 
     {    
      makeSelfMoves = replay[item.Key]; 
      codeFile.ExecuteAll(makeSelfMoves[0], 
       makeSelfMoves[1], makeSelfMoves[2], makeSelfMoves[3]); 

      // i get the error here. uictx is null 
      uiCtx.Post(o => 
      { 
       PrintPieces(codeFile.PieceState()); 
      }, null);        

      System.Threading.Thread.Sleep(1000); 
     } 
    } 
} 
+3

然後,你在運行這段代碼的背景是什麼?控制檯應用程序? –

+0

winform應用程序 –

+0

什麼是創建此對象的實例以及何時? (畢竟,你似乎正在捕獲同步上下文*) –

回答

12

你的代碼關鍵取決於你的類的構造函數的運行時間和位置。創建

  • 類對象太早,之前你的代碼創建Form類的實例或在主調用Application.Run()():當SynchronizationContext.Current將是無效的。這就是Current成員被設置爲WindowsFormsSynchronizationContext的一個實例,該類是知道如何用消息循環封送調用的類。通過將對象實例化代碼移動到主窗體構造函數來解決此問題。

  • 您的類對象是在主UI線程以外的任何線程上創建的。只有Winforms應用程序中的UI線程才能編組調用。通過增加一個構造函數類本聲明診斷此:

     Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId); 
    

而且這一行添加到主Program.cs中()方法。如果「輸出」窗口中的顯示值不同,它將不起作用。通過將對象實例化代碼移動到主窗體構造函數來修復此問題,以確保它可以在UI線程上運行。

+0

好吧,我會記住你的想法..感謝您的幫助 –

+0

這是一個古老的答案,但值得注意的是,Application.Run不是唯一一次WinForms安裝其SynchronizationContext。我發現創建一個新窗體也會導致安裝WindowsFormsSynchronizationContext,並且大概其他控件子類的構造函數會產生相同的效果,儘管我沒有測試過它。 – Drake

+0

我有一個應用程序,我實際上只有'新的Control();'作爲一個聲明本身的一個註釋,說明這樣做是因爲我需要一個同步上下文,否則它會被創建。 – hvd