ラムダ閉鎖またはクラスレベル変数?
-
05-07-2019 - |
質問
ベストプラクティスとは何かについての一般的な質問:
public void Foo()
{
int x = 5;
myControl.Click += (o, e) =>
{
x = 6;
};
}
注意、ラムダイベントハンドラー内で x
変数を使用しています。
または:
public class Bar
{
private int x = 5;
public void Foo()
{
Control myControl = new Control();
myControl.Click += new EventHandler(myControl_Click);
}
private void myControl_Click(object sender, EventArgs e)
{
x = 6;
}
}
ここでは、 x
はクラスのプライベートメンバーであるため、イベントハンドラーでアクセスできます。
今、コード内のどこにも x
を必要としないとしましょう(何らかの理由で)、どの方法がより良い方法ですか?
解決
必要に応じて異なります。最初の例では、イベントハンドラーの副作用はメソッドスコープに制限され、2番目の例では、副作用はインスタンススコープです。 Xはどこでも使用されないため、最初の例でクロージャを使用しても意味がないと思うので、例に基づいて判断することは困難です。
そうは言っても、一般的には、イベントハンドラー(コードで作成したもの)を変数と同様に扱うのが最善です。できるだけ狭い範囲にスコープし、必要に応じてより広いスコープにリファクタリングします。
クロージャーを使用する必要がある ときに強調するより良い例は次のとおりです。
public void Subscribe(Action<string> messageCallBack)
{
myButton.Click += () => messageCallBack("Button was clicked.");
}
これにより、複数のサブスクライバーが許可され、他のサブスクライバーよりもはるかに簡単になります。
private readonly List<Action<string>> callBacks;
public MyClass()
{
callBacks = new List<Action<string>>();
myButton.Click += myButton_Click;
}
private myButton_Click(object sender, EventArgs e)
{
foreach (Action<string> callBack in callBacks)
{
callBack("Button was clicked");
}
}
public void Subscribe(Action<string> messageCallBack)
{
callBacks.Add(messageCallBack);
}
他のヒント
コードの他の場所にxが必要ない場合、ハンドラーはノーオペレーションです-確かにそれはナンセンスな状況です。
xが必要になったら 、Barインスタンスまたはデリゲートインスタンス(または場合によってはデリゲートのコレクション)にスコープする必要があるかどうかを決定する必要があります。
所属していません StackOverflow