C # лямбда реф - PullRequest
       24

C # лямбда реф

4 голосов
/ 26 ноября 2009

Я пытаюсь сделать это, но это не работает. Некоторые предложения?

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, но это не работает.

Что я могу сделать, чтобы это исправить?

EDIT

Я пробовал это, но в другом методе dataSet все еще пуст.

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 ]

8 голосов
/ 26 ноября 2009

При передаче переменной с использованием ключевого слова 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 внутри лямбда-выражения не является той же переменной, что и dataSet вне лямбда-выражения. Что вы можете сделать, это следующее:

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

Теперь у нас есть ссылочный тип со свойством, которое мы можем безопасно изменить внутри лямбда-выражения:

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

}

}

В приведенном выше коде лямбда-выражение обновит свойство DataSet экземпляра DataSetContainer, передаваемого методу Select. Поскольку вы не изменяете сам передаваемый аргумент, а только член этого экземпляра, ключевое слово ref не нужно, и мы также обходим проблему закрытия.

Обновление 2
И теперь, когда я включил свой мозг, я понял, что метод Select делает асинхронный вызов. Вполне вероятно, что код выглядит так, что последняя строка - это метод Select, который будет выполнен задолго до присвоения _dataSet, и в результате это будет null. Чтобы обойти это, вы, вероятно, захотите использовать какой-нибудь механизм сигнализации (например, ManualResetEvent или AutoResetEvent), чтобы знать, когда назначение выполнено.

8 голосов
/ 26 ноября 2009

Переменная i в лямбда-выражении относится к параметру i метода. В качестве обходного пути вы можете сделать так, чтобы он ссылался на глобальную переменную (грязное решение).

Кстати, вы не можете захватывать переменные ref и out в лямбдах , но вы можете иметь их в качестве параметров. Вам нужно изменить сигнатуру вашего делегата и реализацию метода, получающего делегат, что может не подойти:

(out int i) => { i = 10; }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...