问题 将lambda表达式用于事件处理程序的最佳实践


在发现lambda表达式及其作为匿名函数的用法之后,我发现自己编写了许多更为琐碎的事件,例如:

txtLogin.GotFocus += (o, e) =>
{
    txtLogin.Text = string.Empty;
    txtLogin.ForeColor = SystemColors.ControlText;
};
txtLogin.LostFocus += (o, e) =>
{
    txtLogin.Text = "Login...";
    txtLogin.ForeColor = SystemColors.InactiveCaptionText;
};

我也离开了只调用其他函数的事件处理程序,用同样的小lambda替换它们:

backgroundWorker.DoWork += (o, e) => DatabaseLookup.Open(e.Argument as string);

我发现了一些类似的问题 表现问题 并指出你 无法删除它们,但我还没有发现任何解决这个简单问题的问题 这是一个好主意吗?

使用lambdas是否被认为是一种良好的形式,还是更多的经验程序员看不起这个?它是否在难以找到的位置隐藏事件处理程序,还是通过减少普通事件处理程序的数量来使代码成为服务?


1958
2017-07-14 16:14


起源



答案:


这是一个非常合理的想法 - 但在这种特殊情况下,我会使用匿名方法:

txtLogin.LostFocus += delegate
{
    txtLogin.Text = "Login...";
    txtLogin.ForeColor = SystemColors.InactiveCaptionText;
};

好处是您不必指定参数 - 这使您更清楚地知道不使用它们。这是 只要 匿名方法优于lambda表达式的优点。

性能影响几乎总是可以忽略不计。如果你,之后无法删除它们是一个非常现实的问题  需要能够删除处理程序,但我发现我经常不这样做。 (Reactive Extensions有一个很好的方法 - 当你订阅一个可观察的序列时,你会得到一个 IDisposable 如果您调用它,将删除订阅。井井有条。)


15
2017-07-14 16:21





实际上,它认为它将事件处理程序放在易于查找的位置,即紧接着它所分配的事件的名称。

很多时候,你会看到事件处理程序,如:

 void Text1_KeyDown(....) {....}

附加到txtFirstName的KeyUp事件,因为在使用Intellisense创建处理程序后,有人决定重命名文本框,并且KeyUp工作得更好。使用Lambda,对象,事件和功能都在一起。


1
2017-07-14 16:22





这是一个棘手的问题。我记得在读书 代码完成 关于一些(聪明的)人们如何说你应该保持控制流程尽可能简单,许多人争论一个方法的单一进入和退出点,因为不这样做会使程序更难以遵循。

Lambdas离这个更远了,在某些情况下很难跟踪正在发生的事情,控制从一个地方跳到另一个地方。

基本上,我认为这可能是一个坏主意,但它也很强大,让生活更轻松。我当然使用它们相当数量。总之,请谨慎使用!


0
2017-07-14 16:25



限制自己到一个出口点是可读性灾难的一个秘诀,IMO。如果我在一行之后知道方法的结果(例如因为它是一个特例),那么就没有理由让读者按照方法的其余部分来到达出口点。 - Jon Skeet
我同意,我总是赞成提前退出。但我知道有些人反对这一点。 - Grant Crofton
我的理念是,通常希望避免函数在具有副作用的第一个语句和最后一个这样的语句之间退出,除了从a中返回一个值。 try block可能比在块中设置变量并从外部返回变量更干净。 - supercat


答案:


这是一个非常合理的想法 - 但在这种特殊情况下,我会使用匿名方法:

txtLogin.LostFocus += delegate
{
    txtLogin.Text = "Login...";
    txtLogin.ForeColor = SystemColors.InactiveCaptionText;
};

好处是您不必指定参数 - 这使您更清楚地知道不使用它们。这是 只要 匿名方法优于lambda表达式的优点。

性能影响几乎总是可以忽略不计。如果你,之后无法删除它们是一个非常现实的问题  需要能够删除处理程序,但我发现我经常不这样做。 (Reactive Extensions有一个很好的方法 - 当你订阅一个可观察的序列时,你会得到一个 IDisposable 如果您调用它,将删除订阅。井井有条。)


15
2017-07-14 16:21





实际上,它认为它将事件处理程序放在易于查找的位置,即紧接着它所分配的事件的名称。

很多时候,你会看到事件处理程序,如:

 void Text1_KeyDown(....) {....}

附加到txtFirstName的KeyUp事件,因为在使用Intellisense创建处理程序后,有人决定重命名文本框,并且KeyUp工作得更好。使用Lambda,对象,事件和功能都在一起。


1
2017-07-14 16:22





这是一个棘手的问题。我记得在读书 代码完成 关于一些(聪明的)人们如何说你应该保持控制流程尽可能简单,许多人争论一个方法的单一进入和退出点,因为不这样做会使程序更难以遵循。

Lambdas离这个更远了,在某些情况下很难跟踪正在发生的事情,控制从一个地方跳到另一个地方。

基本上,我认为这可能是一个坏主意,但它也很强大,让生活更轻松。我当然使用它们相当数量。总之,请谨慎使用!


0
2017-07-14 16:25



限制自己到一个出口点是可读性灾难的一个秘诀,IMO。如果我在一行之后知道方法的结果(例如因为它是一个特例),那么就没有理由让读者按照方法的其余部分来到达出口点。 - Jon Skeet
我同意,我总是赞成提前退出。但我知道有些人反对这一点。 - Grant Crofton
我的理念是,通常希望避免函数在具有副作用的第一个语句和最后一个这样的语句之间退出,除了从a中返回一个值。 try block可能比在块中设置变量并从外部返回变量更干净。 - supercat