C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト


■86453 / )  Re[3]: 空の delegate は null なの?
□投稿者/ 魔界の仮面弁士 (1560回)-(2018/01/30(Tue) 18:27:56)
No86407 (774RR さん) に返信
> そういやオイラ event ハンドラにはいつも「何もしない」ハンドラを割り振ってますな。

それって、イベントを提供する側の話でしょうか。
それとも、イベントを利用する側の話でしょうか。
 button1.Click += delegate {}

いずれにしても、EventHandler や EventHandler<TEventArgs> に限った話ですよね。

C# では、戻り値を返すイベントを定義できますが、
この場合、「何もしない ハンドラ」を割り当てるわけには行かないはず。
 public delegate bool FooDelegate(int x);
 public event FooDelegate Foo;


一方 VB.NET の場合、『戻り値を持ったイベント』を定義しようとすると
Visual Basic ではコンパイルエラー(BC31084)となる仕様です。
定義済みのものを利用する分には、VB6 でも VB.NET でも可能なのですが。


実際のところ、複数のメソッド呼び出しを束ねるのはイベントの場合ぐらいで、
ましてや戻り値を持つメソッドを連結させることは非常に稀だとは思いますが、
もしも個々の戻り値を個別に受け取る必要がある場合は、そのデリゲートの
GetInvocationList メソッドを利用できるようになっています。



> // メンバ宣言して new してない段階では d は null なのは納得

未初期化のローカル変数 d に対しては
 d = Method1;
は実行できても、
 d += Method1;
はコンパイルエラーになりますね(CS0165)。当然のことではありますが。



No86445 (774RR さん) に返信
> おお non-static メンバ関数ではなくて static メンバ関数の syntax sugar だったわけですか・・・

ちなみにデリゲートは、インスタンスメソッドの呼び出しに最適化されているため、
静的メソッドの呼び出しだと、効率がかなり悪いそうです。
これについて、カリー化(curried delegate)で回避できます。
http://ufcpp.net/study/csharp/functional/miscdelegateinternal/


> C++ では += が static メンバにはなりえないのでそういう認識でいました。
> this が必須のような構文をしておいて実は static っつーのはずいぶん罪作りな糖衣構文っすね。

delegate 以外でも、
 string s = null;
 s += null;
と書けますけれどね。しかも上記の結果は、null ではなく string.Empty です。

# 上記は『s = System.String.Concat(null, null);』相当


> # += が Combine の糖衣構文であるとはどこに書いてあるんだろう・・・探す気力なし

同じ意味になると、大昔に TechEd あたりで聞いたような気がするのですが、
済みません、私もうろ覚えなので情報ソースは提示できないです。

公式資料として書いたものがあるかどうかまでは分からないので、
糖衣構文と呼べるかどうかは自信がなくなってきました。今更ですが。


ただ言語仕様面で捉えてみると、+= が Combine というよりは、
「a += b」が「a = a + b;」の糖衣構文と捉えた方が良いかと思っています。

「変数 a」の型が、「a + b」の演算が返す型と同じ(あるいは暗黙変換可能)でない場合、
a += b; はコンパイルエラーとなります。

// これはエラー
int a = 0;
a += 0L;

// これは OK
float b = 0F;
b += 0L;


ただしデリゲートが event 化されている場合は話が変わってきます。

イベントは特別扱いされており、デリゲート型変数とは違って、
演算子として += と -= しか使えません。(デリゲートなら + や - や = も使える)
しかも代入式の左辺にしか記述できないという制限付き。

この制限があるため、匿名メソッドやラムダ式を、
 button2.Click += delegate { MessageBox.Show("Test"); };
のように、変数を介さずにイベントハンドラとして直接割り当ててしまうと、
後で解除あるいはクリアできずに難儀することになりますね。


ちなみに上記の += 処理は、
 button2.add_Click(new EventHandler(delegate { MessageBox.Show("Test"); }));
相当の処理としてコンパイルされます。

といっても、C# からの add_Click メソッドの呼び出しは禁止されているのですけれども。
(JScript.NET や PowerShell の場合は、add_Click メソッドを使って割り当てます)
解決済み
返信 編集キー/


管理者用

- Child Tree -