我正在尝试这样做,但它不起作用。一些建议?
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;
}
答案 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
。为了解决这个问题,您可能希望使用某种信令机制(例如ManualResetEvent
或AutoResetEvent
)来了解分配何时完成。