方法订阅vs lambda委托订阅 - 哪个以及为什么?

时间:2010-08-31 15:04:33

标签: c# .net delegates lambda

我看到有些人倾向于将方法交给回调/事件,然后有时只是把他们交给lambdas。

任何人都能说出两者之间的差异吗?我原本以为它们是相同的,但是我所看到的不一致有时让我想知道是否有一个比另一个更好的情况?显然,如果有大量的代码,它不应该是现场lambda,否则......

你们是否可以概述两者之间的差异(如果有的话),并概述两者在两者可用时选择的规则?

4 个答案:

答案 0 :(得分:7)

两者之间最大的区别之一是您可以轻松取消订阅活动。使用基于方法的方法取消订阅是一个简单的操作,只需使用原始方法

m_button.Click += OnButtonClick; 
...
m_button.Click -= OnButtonClick;

使用lambdas并不是那么简单。您必须存储lambda表达式,并在以后用于取消事件

m_button.Click += delegate { Console.Write("here"); }
...
// Fail
m_button.Click -= delegate { Console.Write("here"); } 

EventHandler del = delegate { Console.Write("here"); }
m_button.Click += del;
...
m_button.Click -= del;

这实际上减损了使用lambda表达式的便利性。

答案 1 :(得分:2)

在大多数拥有lambda(包括C#)的语言中,在方法中创建lambda会创建一个闭包 - 也就是说,声明方法中的局部变量对lambda是可见的。这是我所知道的最大区别。

除此之外,除非您以某种方式命名您的事件处理程序,以另一种函数可访问的方式,您将发现以后很难分离事件处理程序。这可以通过将委托存储在实例级或类级变量中来实现,但它可能有点难看。

答案 2 :(得分:1)

使用Lambda的最大原因是延迟执行,即您定义了要执行的操作,但直到稍后才会有参数。您通常不会将lambdas用于事件和回调;你使用匿名方法。

对于您不需要取消订阅的简单事件,对事件和回调使用匿名方法是可以的。对我来说,最重要的决定因素是我宣称它。我不打算将表单的事件处理程序声明为匿名方法,但如果我有一个短暂的需要连接到事件,它可能没问题。

一般来说,我使用实际的方法来回调和事件而不是匿名方法;我正在处理的事件与对象的生命周期有关,而不是与方法的生命周期有关,我发现在代码中更清楚地将回调明确定义在钩住它们的函数外部。其中一些是个人偏好。

答案 3 :(得分:0)

在大多数情况下,几乎没有实际差异。使用哪一个主要是个人偏好(即您希望代码看起来像)。在某些情况下,有一些实际的理由偏爱一个:

  1. the accepted answer所述,取消订阅匿名方法比取消订阅命名方法更复杂。没有名称,除了在运行时创建的委托实例(声明匿名方法)之外,没有办法引用匿名方法。使用命名方法,可以取消订阅该委托,而无需保留对原始委托(或其等同物)的引用。
  2. 另一方面,更喜欢lambda表达式的原因是事件的处理程序是声明lambda / anonymous方法的named方法的唯一实现细节。这可以帮助将这些实现细节保持为使用它们的方法的私有和本地。
  3. 可能使用lambda表达式的另一个原因是,是否需要“调整”委托类型。即您确实希望调用命名方法来处理事件,但该方法的签名与事件所需的签名不同。这可能是您希望将方法重用于不同事件或其他情况的情况,其中事件中的某些参数可能不适用。另一种情况可能是您想要为事件可能不提供的值引入新参数(例如,对象集合的索引都具有您想要订阅的相同事件)。
  4. 有时会出现一种特殊情况,即可以选择是单独使用命名方法,还是使用匿名方法然后调用该命名方法。重要的是要注意,在没有其他实际原因选择其中一个的情况下,使用命名方法在此特定情况下稍微更有效,因为它从调用中删除了一个方法调用。在实践中,你可能永远不会注意到差异,但它只是开销,所以如果没有特定的,实际的理由产生它,人们应该避免它,即直接订阅命名方法。