イベントハンドラーのラムダ式の使用


114

現在、次のように宣言されているページがあります。

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の外部でイベントハンドラーを作成することに慣れています。私の質問です。これにラムダメソッドを使用するときに注意する必要のあるパフォーマンスの欠点や落とし穴はありますか?確かに簡潔なので、私はそれを好みますが、使用するためにパフォーマンスを犠牲にしたくありません。ありがとう。

回答:


117

コンパイラーはラムダ式を同等のデリゲートに変換するため、パフォーマンスへの影響はありません。ラムダ式は、コンパイラーが、使い慣れたまったく同じコードに変換する言語機能にすぎません。

コンパイラーは、必要なコードを次のようなものに変換します。

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の内部に置くことと、外部に置くことの欠点はありませんか?
クリストファーガルシア

1
一般的な規則は、OnInitメソッドにイベントハンドラーをアタッチClickすることですが、ページのロード後にボタンのイベントが発生するため、この例は問題ありません。
Andrew Hare

8
デリゲートへの参照を保持しないと、イベントの登録を解除できないことに注意してください。
snarf 2013年

3
「まったく同じコード」は少し誤解を招きやすいです。封入方法からローカル変数を参照する場合、少なくとも、ラムダ式は、メソッドに翻訳されない、ローカル変数の現在の値を格納する閉鎖オブジェクトのようなもの。
またはMapper

66

パフォーマンスに関しては、名前付きメソッドと同じです。大きな問題は、次の場合です。

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

おそらく別のラムダを削除しようとし、元のラムダはそのままにします。つまり、ハンドラーを削除できるようにしたい場合を除いて、問題はないということです。


3
たぶん ……」?それはウィルこれまで、このようなAの状況で正しいハンドラを削除しますか?
またはMapper、

1
@ORMapper:ラムダが変数をキャプチャする場合、正しいハンドラーを削除できません。他の状況では、それはコンパイラ次第です。
Gabe

本当に?興味深いので、同じように見える2つの匿名関数(wlogには空の本文があります)を登録し、さらに空の本体を持つ-=別の匿名関数の登録を解除(を使用して)すると、2つのイベントハンドラーのどちらが基本的に未定義になるか削除されるか、またはそれらのいずれかがまったく削除されるかどうか?
またはMapper、

4
@ORMapper:はい。コンパイラーは、セマンティクスが同じ(コードが同じである必要はないが、同じことを行う必要がある)場合に同等のデリゲートを作成し、同じ変数インスタンスをキャプチャすることができます(必須ではありません)。同じ変数ですが、それらの変数の同じインスタンス)。詳細については、C#仕様のセクション7.10.8(デリゲート等価演算子)を参照してください。
Gabe

12
本当にラムダを使用したいがイベントを削除する必要がある場合は、常にローカル変数/フィールドにオブジェクトを保持し、それを削除できます。例var event = (o, e) => doSomething(); handler += event; doSomethingElse(); handler -= event;
Wai Ha Lee

44
EventHandler handler = (s, e) => MessageBox.Show("Woho");

button.Click += handler;
button.Click -= handler;

1
トピックから外れていますが、非常に役立つ情報です(問題はパフォーマンスに関するものです)。
ステフェイン・グーリッホン

4
メモリ使用量はパフォーマンスの低下につながる可能性があるため、正確にトピック外ではありません。
Vladius 2016年

3
ハンドラ自体に自分自身を削除することも有用であろう:c# EventHandler handler = null; handler = (s, e) => { MessageBox.Show("Woho"); button.Click -= handler;}
Vladius

2

私が認識している、またはこれまでに遭遇したことのあるパフォーマンスへの影響はありません。私がその「構文上のシュガー」を知っていて、デリゲート構文を使用するのと同じことまでコンパイルされている場合などです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.