次の方法で共有


EventHandler内でメンバとsender、どちらを使うか

質問

2012年12月17日月曜日 1:06

EventHandler内で、イベントを発生させたオブジェクト(クラスのメンバ)を参照したい場合、メンバとsenderのキャスト、どちらが好ましいでしょうか。

つまり、下のようなクラスでは、obj.MyEventのイベントハンドラとして、obj_MyEvent1とobj_MyEvent2のどちらのように書くのが好ましいでしょうか。その理由もご教授ください。

class sample
{
private EventSourceClass obj;

private void obj_MyEvent1(object sender, EventArgs e)
    {
    this.obj.DoSomething();
    }

private void obj_MyEvent2(object sender, EventArgs e)
    {
    ((EventSourceClass)sender).DoSomething();
    }
}

よろしくお願いいたします。

すべての返信 (5)

2012年12月17日月曜日 1:32 ✅回答済み | 1 票

この辺は好き好きだと思うのであくまでも私個人の考え方として、ですが・・・

私は後者(sender)ですね。
理由は
・この関数を再利用する際にsenderとして別のオブジェクトを渡せるため、汎用性が増すこと。
・WPFの場合、Nameを持たないコントロールを特定するにはsenderしか手段がない。
・スコープがより限定的(まあこれは気分の問題(笑))。
ぐらいですかね。
あと、何となくメンバ変数に直アクセスって好きじゃないという感覚的な好みもあります。

ま、参考までに。


2012年12月17日月曜日 1:44 ✅回答済み | 1 票

通常は前者のthis.obj.DoSomething(); で良いと思います。thisも省けますから、簡潔にobj.DoSomething(); と書けます。理由は、コードが短く読みやすいからです。ただ、コードが短ければどのような場合でも可読性が良いことにはならない思います。
つまり、((EventSourceClass)sender).DoSomething();は、このイベントの発生元を操作していることが明確であり、そちらの方が読みやすいという意見もあると思うからです。例えば、複数人が共同でコードを書く場合、どのような場合でもキャスト形式に統一しておくと、逆に可読性が上がる場合もあると思います。
少しご質問から離れると思いますが、このイベントハンドラ内で、あるメソッドの引数として渡す場合は、キャストを使用している方がわかりやすいかもしれません。
(例)
Hogeメソッド((EventSourceClass)sender);

ところで、EventSourceClass、およびDoSomethingメソッドが具体的に書かれていないのですが、例えば、EventSourceClassがTextBoxを継承したクラスであり、DoSomethingが継承元に定義してあるClearメソッドであれば、
((TextBox)sender).Clear(); と書けます。このコードは独自に定義したクラスが出てこない汎用的なコードです。汎用的であれば使い回しがしやすいというメリットがありますので、この点を考慮するという視点もあって良いと思います。

なにやらまとまらない話になってしまいましたが、開発を行っている環境や状況などによって、どのようなポリシー(コーディング規約)を持つかによって変わると思いますので、どちらが良いとは決められないのではないかと思います。私もいろいろな意見を聞いてみたいと思います。

#(追記) キャストが発生する場合はおそらくパフォーマンスが劣ると思いますが、人間が感知できないレベルでしょうから、あまり気にしなくても良いと思います。これも私の個人的な考えであり、いや、できるだけパフォーマンスが劣らない方法で書くというポリシーもあるいでしょうし、それを否定するものではありません。

★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/


2012年12月17日月曜日 2:20 | 1 票

どちらが好ましいということはありません。

sender がどこかのメソッドのローカル変数なら sender を使わざるを得ません。

Form 上のコントロールのイベントハンドラーであれば呼び出し元のコントロール以外のコントロールも操作することなんてよくあることです。その中で呼び出し元コントロールだけ sender を使うことに違和感がある場合もあるでしょう。また、あるコントロールのインスタンス 3 つが連動している場合、

void MyEventHander1(object sender, EventArgs e)
{
    if (isValid(((MyControl)sender).Value, myControl2.Value, myControl3.Value))
    {
    }
}

void MyEventHander2(object sender, EventArgs e)
{
    if (isValid(myControl1.Value, ((MyControl)sender).Value, myControl3.Value))
    {
    }
}
void MyEventHander3(object sender, EventArgs e)
{
    if (isValid(myControl1.Value, myControl2.Value, ((MyControl)sender).Value))
    {
    }
}

でなく、

void MyEventHander(object sender, EventArgs e)
{
    if (isValid(myControl1.Value, myControl2.Value, myControl3.Value))
    {
    }
}

なら 1 つで済みます。


2012年12月17日月曜日 5:20

汎用性ということまでは考えていませんでした。

とても勉強になります。ありがとうございました。


2012年12月17日月曜日 5:21

>何となくメンバ変数に直アクセスって好きじゃないという感覚的な好みもあります。

私も同じ感覚だったのですが、間違いではないことが確認できてすっきりできました。

ありがとうございました。