C#lambda ref out

Joo*_*ooj 4 .net c# lambda .net-3.5

我正在尝试这样做,但它不起作用.一些建议?

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();
                                    };
                    });
}
Run Code Online (Sandbox Code Playgroud)

为什么我不能将test_i设置为3?我也试过ref和out,但它不起作用.

我该怎么办才能修复它?

编辑

我试过这个,但是这个方法dataSet的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;
  }
Run Code Online (Sandbox Code Playgroud)

Meh*_*ari 8

ilambda表达式中的变量指i的是方法的参数.作为一种解决方法,您可以使其引用全局变量(脏解决方案).

顺便说一下,你不能在lambdas中捕获refout变量,但你可以将它们作为参数.您需要更改委托的签名和接收委托的方法的实现,这可能不合适:

(out int i) => { i = 10; }
Run Code Online (Sandbox Code Playgroud)


Fre*_*örk 8

使用ref关键字传递变量时,不能在lambda表达式中使用它.尝试在lambda中使用局部变量并在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
}
Run Code Online (Sandbox Code Playgroud)

更新
响应更新的答案:您的问题是_dataSetlambda表达式内部与lambda表达式之外的dataSet不是同一个变量.你能做的是以下几点:

class DataSetContainer
{
    public DataSet DataSet { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

现在我们有一个带有属性的引用类型,我们可以在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;
       };
    });

}
Run Code Online (Sandbox Code Playgroud)

}

在上面的代码中,lambda表达式将更新传递给方法DataSetDataSetContainer实例的属性Select.由于您不是修改传递的参数本身,而只是修改该实例的成员,因此不需要ref关键字,我们也解决了关闭问题.

更新2
现在,当我打开我的大脑时,我意识到该Select方法会进行异步调用.很可能因为代码看起来最后一行是Select方法将在_dataSet被分配之前很久执行,因此它将是null.为了解决这个问题,您可能希望使用某种信令机制(例如ManualResetEventAutoResetEvent)来了解分配何时完成.