2009-11-26 49 views
4

我正在嘗試這樣做,但它不起作用。一些建議?C#lambda ref out

int test_i = 0; 
DoSomethingThatTakesAgesAndNeedsToUpdateUiWhenFinished(test_i); 
test_i <- still is 0 and not 3!!! 

public void DoSomethingThatTakesAgesAndNeedsToUpdateUiWhenFinished(int i) 
{ 
    DisableUi(); 
    m_commandExecutor.ExecuteWithContinuation(
       () => 
        { 
         // this is the long-running bit 
         ConnectToServer(); 
         i = 3; <-------------------------- 
         // This is the continuation that will be run 
         // on the UI thread 
         return() => 
            { 
             EnableUi(); 
            }; 
        }); 
} 

爲什麼我不能將test_i設置爲3?我也試過裁判,但它不起作用。

我能做些什麼來解決它?

編輯

我已經試過這一點,但ouside這種方法的數據集仍然是空的。

public static void Select(DataGridView dataGridView, ref DataSet dataSet, params object[] parameters) 
    { 
    var _dataSet = dataSet; 
    AsyncCommandExecutor commandExecutor = new AsyncCommandExecutor(System.Threading.SynchronizationContext.Current); 
    commandExecutor.ExecuteWithContinuation(
    () => 
    { 
     // this is the long-running bit 
     _dataSet = getDataFromDb(parameters); 

     // This is the continuation that will be run on the UI thread 
     return() => 
     { 
      dataGridView.DataSource = _dataSet.Tables[0].DefaultView; 
     }; 
    }); 
    dataSet = _dataSet; 
    } 
+0

我更新了我的答案。希望它有助於:o) – 2009-11-30 17:42:03

回答

8

當通過使用關鍵字ref的變量,你不能用它裏面的λ表達。嘗試使用拉姆達內部的局部變量,並將外面的ref變量,如果可能的話(有些簡單的例子):

private static void Main(string[] args) 
{ 
    int i = 0; 
    DoSomethingThatTakesAgesAndNeedsToUpdateUiWhenFinished(ref i); 
    Console.WriteLine(i); 
} 


public static void DoSomethingThatTakesAgesAndNeedsToUpdateUiWhenFinished(ref int i) 
{ 
    int temp = i; 
    Thread t = new Thread(() => 
    { 
     temp = 3; // assign the captured, local variable  
    }); 
    t.Start(); 
    t.Join(); 

    i = temp; // assign the ref parameter 
} 

更新
爲響應更新的回答:你的問題是,_dataSet內lambda表達式與lambda表達式外部的dataSet不是同一個變量。你可以做的是:

class DataSetContainer 
{ 
    public DataSet DataSet { get; set; } 
} 

現在我們有一個屬性的引用類型,我們可以安全地在lambda表達式中修改:

public static void Select(DataGridView dataGridView, 
          DataSetContainer dataSetContainer, 
          params object[] parameters) 
{ 
    AsyncCommandExecutor commandExecutor = new AsyncCommandExecutor(System.Threading.SynchronizationContext.Current); 
    commandExecutor.ExecuteWithContinuation(
    () => 
    { 
     // this is the long-running bit 
     dataSetContainer.DataSet = getDataFromDb(parameters); 

     // This is the continuation that will be run on the UI thread 
     return() => 
     { 
      dataGridView.DataSource = _dataSet.Tables[0].DefaultView; 
     }; 
    }); 

} 

}

在上面的代碼,lambda表達式將更新傳遞給Select方法的DataSetContainer實例的DataSet屬性。由於您沒有修改傳入的參數本身,只有該實例的成員,因此不需要ref關鍵字,並且我們還解決了關閉問題。

更新2
而現在,當我在我的大腦切換,我意識到Select方法使異步調用。這很可能是因爲代碼看起來最後一行是Select方法將在_dataSet被分配很久之前執行,因此它將是null。爲了解決這個問題,您可能需要考慮使用某種信號機制(如ManualResetEventAutoResetEvent)來了解分配何時完成。

+0

是否有可能像我的例子中使用它,但有一個dataSet,而不是int我? – Jooj 2009-11-30 11:49:42

+0

@Jooj:如果你傳遞一個引用類型,你應該可以在lambda表達式中修改它的成員屬性/字段。 – 2009-11-30 12:08:20

+0

請看我最後的帖子。 – Jooj 2009-11-30 15:31:48

7

在lambda表達的i變量指的是方法的參數i。作爲一種解決方法,您可以使其引用全局變量(髒解決方案)。

順便說一句,you can't capture ref and out variables in lambdas,但你可以讓他們作爲參數。你需要改變你的委託的簽名和方法的接受委託實施,這可能不適合:

(out int i) => { i = 10; }