【问题标题】:Using lambda expressions for event handlers将 lambda 表达式用于事件处理程序
【发布时间】:2011-01-28 17:35:12
【问题描述】:

我目前有一个页面声明如下:

public partial class MyPage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //snip
        MyButton.Click += (o, i) =>
        {
            //snip
        }
    }
}

我最近才从 1.1 迁移到 .NET 3.5,所以我习惯于在 Page_Load 之外编写事件处理程序。我的问题是;在使用 lambda 方法时,我应该注意哪些性能缺陷或陷阱?我更喜欢它,因为它肯定更简洁,但我不想牺牲性能来使用它。谢谢。

【问题讨论】:

    标签: c# performance events lambda


    【解决方案1】:

    没有性能影响,因为编译器会将您的 lambda 表达式转换为等效的委托。 Lambda 表达式只不过是一种语言功能,编译器会将其翻译成您习惯使用的完全相同的代码。

    编译器会将你拥有的代码转换成这样的:

    public partial class MyPage : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //snip
            MyButton.Click += new EventHandler(delegate (Object o, EventArgs a) 
            {
                //snip
            });
        }
    }
    

    【讨论】:

    • 我明白了。那么将这些处理程序放在 Page_Load 内部与将它们放在外部也没有缺点吗?
    • 流行的约定是在OnInit方法中附加事件处理程序,但是由于页面加载后会引发按钮的Click事件,所以这个例子很好。
    • 需要注意的是,如果不保留对代理的引用,您将无法取消订阅该事件。
    • “完全相同的代码”有点误导;至少在从封闭方法引用局部变量时,lambda 表达式不会被转换为方法类似于存储局部变量当前值的闭包对象。
    【解决方案2】:

    在性能方面它与命名方法相同。最大的问题是当您执行以下操作时:

    MyButton.Click -= (o, i) => 
    { 
        //snip 
    } 
    

    它可能会尝试删除不同的 lambda,而将原始的 lambda 保留在那里。所以教训是,除非您还希望能够删除处理程序,否则没关系。

    【讨论】:

    • “它会可能尝试...”?在这种情况下它会永远删除正确的处理程序吗?
    • @O.R.Mapper:如果 lambda 捕获变量,则无法删除正确的处理程序。在其他情况下,这取决于编译器。
    • 真的吗?有趣 - 所以,如果我注册两个看起来相同的匿名函数(wlog 有一个空主体),然后我取消注册(使用-=)另一个也有一个空主体的匿名函数,那么这两者中的哪一个本质上是未定义的事件处理程序将被删除,或者它们中的任何一个是否将被删除?
    • @O.R.Mapper:是的。如果它们具有相同的语义(代码不必相同,但它们必须做相同的事情)并捕获相同的变量实例(不仅仅是相同的变量,但这些变量的相同实例)。有关所有详细信息,请参阅 C# 规范的第 7.10.8 节(委托相等运算符)。
    • 如果您真的想使用 lambda 但需要删除事件,您可以始终将对象保留在局部变量/字段中,然后将其删除,例如var event = (o, e) => doSomething(); handler += event; doSomethingElse(); handler -= event;
    【解决方案3】:
    EventHandler handler = (s, e) => MessageBox.Show("Woho");
    
    button.Click += handler;
    button.Click -= handler;
    

    【讨论】:

    • 非常有用的信息,虽然不是主题(问题是关于性能)。
    • 并非完全偏离主题,因为内存使用会导致性能下降。
    • 在处理程序本身中删除自身也可能会有所帮助:c# EventHandler handler = null; handler = (s, e) => { MessageBox.Show("Woho"); button.Click -= handler;}
    【解决方案4】:

    据我所知,它只是“语法糖”并编译成与使用委托语法等相同的东西,没有我知道或曾经遇到过的性能影响。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多