C # lambda ref out

I am trying to do this, but it will not work. Some suggestions?

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

Why can't I set test_i to 3? I also tried ref and out, but it does not work.

What can I do to fix this?

EDIT

I tried this, but the ouside of this dataSet method is still empty.

 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; } 
+4
source share
2 answers

When passing a variable using the ref keyword, you cannot use it inside a lambda expression. Try using a local variable inside lambda and assign the ref variable outside of it, if possible (somewhat simplified example):

 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 } 

Update
In response to the updated answer: your problem is that the _dataSet inside the lambda expression is not the same variable as the dataSet outside the lambda expression. You can do the following:

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

Now we have a reference type with a property that can be safely changed inside the lambda expression:

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

}

In the above code, the lambda expression will update the DataSet property of the DataSetContainer instance passed to the Select method. Since you are not changing the passed argument itself, but only a member of this instance, there is no need for the ref keyword, and we also bypass the closure problem.

Update 2
And now that I have turned on my brain, I understand that the Select method makes an asynchronous call. It is very likely that the code looks like the last line is the Select method, which will be executed long before _dataSet , and as a result it will be null . To get around this, you probably want to examine some kind of signaling mechanism (e.g. ManualResetEvent or AutoResetEvent ) to know when the assignment is being executed.

+8
source

The variable i in the lambda expression refers to the parameter i method. As a workaround, you can make this a reference to a global variable (dirty solution).

By the way, you cannot write ref and out variables to lambdas , but you can use them as parameters. You need to change the signature of your delegate and the implementation of the method receiving the delegate, which may be unacceptable:

 (out int i) => { i = 10; } 
+7
source

All Articles