我有以下方法
private void SetProcessDocumentStatus(string status)
{
var setStatusWith = new Action<string>(
statusValue => processDocumentStatusLabel.Text = statusValue);
if (processDocumentStatusLabel.InvokeRequired)
processDocumentStatusLabel.Invoke(
(MethodInvoker)(() => setStatusWith(status)));
else
setStatusWith(status);
}
从上面的代码中,我将动作封装到setStatusWith
中。
该行为是否应重构为另一种方法如下?
private void SetProcessDocumentStatusWith(string status)
{
processDocumentStatusLabel.Text = status;
}
private void SetProcessDocumentStatus(string status)
{
if (processDocumentStatusLabel.InvokeRequired)
processDocumentStatusLabel.Invoke(
(MethodInvoker)(() => SetProcessDocumentStatusWith(status)));
else
SetProcessDocumentStatusWith(status);
}
我想知道是否应该在代码中谨慎使用“Action”委托。
答案 0 :(得分:5)
你所拥有的东西对我来说似乎非常清楚。将lambda移动到单独的函数会增加代码行但不清晰。
我可能会把第一行写成:
Action<string> setStatusWith =
statusValue => processDocumentStatusLabel.Text = statusValue;
但我不知道哪种方式通常是首选。
答案 1 :(得分:2)
在示例中,您使操作接受参数:Action<string>
,但之后您只传递相同的参数status
。所以它不需要接受参数 - 也许你不知道lambda捕获变量的能力?
private void SetProcessDocumentStatus(string status)
{
Action setStatusWith = () => processDocumentStatusLabel.Text = status;
if (processDocumentStatusLabel.InvokeRequired)
processDocumentStatusLabel.Invoke(() => setStatusWith());
else
setStatusWith();
}
或者调整Alan Jackson的优秀答案:
private void SetProcessDocumentStatus(string status)
{
processDocumentStatusLabel.Run(ctrl => ctrl.Text = status);
}
public static class ControlExtensions
{
public static void Run<T>(this TControl control, Action<TControl> action)
where TControl : Control
{
if (control.InvokeRequired)
control.Invoke(() => action(control));
else
action(control);
}
}
这里我已经将Action作为参数取而代之。此外,我已将辅助方法变为扩展,这似乎是合理的。
答案 2 :(得分:1)
使用Action委托没有任何内在错误。我之所以说你应该有两个单独的方法的唯一原因是,如果你觉得你需要绕过检查以查看InvokeRequired属性是否为true并且调用必须被编组。但是,我认为没有明确的理由这样做。
就个人而言,我认为检查InvokeRequired然后编组调用自己的代码是个坏主意。我更喜欢调用者不得不意识到他们所处的环境(是UI线程还是没有),然后决定是否编组调用。
答案 3 :(得分:1)
如果有的话,我会包装逻辑来执行函数中的调用,因为这是将要多次使用的逻辑(基本上所有可以设置为异步的函数)。
private void SetProcessDocumentStatus(string status)
{
RunOnControl<string>(
processDocumentStatusLabel,
statusValue => processDocumentStatusLabel.Text = statusValue,
status);
}
private void RunOnControl<T>(Control control, Action<T> action, T param)
{
if (control.InvokeRequired)
control.Invoke(action, param);
else
action(param);
}