C#lambda ref out

时间:2009-11-26 10:15:01

标签: c# .net .net-3.5 lambda

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

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?我也试过ref和out,但它不起作用。

我该怎么做才能解决它?

修改

我已经尝试了这个,但是这个方法的数据集仍然是空的。

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

2 个答案:

答案 0 :(得分:8)

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

顺便说一下,you can't capture ref and out variables in lambdas,但你可以将它们作为参数。您需要更改委托的签名和接收委托的方法的实现,这可能不合适:

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

答案 1 :(得分: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
}

<强>更新
响应更新后的答案:您的问题是lambda表达式中的_dataSet与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表达式将更新传递给DataSet方法的DataSetContainer实例的Select属性。由于您没有修改传递的参数本身,而只是修改该实例的成员,因此不需要ref关键字,我们也解决了关闭问题。

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

相关问题