2009年01月19日

えっ、ラムダ式 はデリゲート型ではないため、型 'object[]' に変換できません。?

  
System.Windows.Threading.Dispatcherクラスの

public DispatcherOperation BeginInvoke (
DispatcherPriority priority,
Delegate method,
Object arg,
params Object[] args
)

の引数 argsにラムダ式を渡そうとしたら、

ラムダ式 はデリゲート型ではないため、型 'object[]' に変換できません。


というエラーメッセージが出てきた。
そうか、object型には変換できないのか、残念。

でも、コンパイラが出すこのメッセージはなんか変?
これをこの表現どおりに読めば、デリゲート型は、object[]に変換できるということになるのだが、もちろんそんなはずはない。

代入先が(型'object' であり)デリゲートで型ではないため、ラムダ式を 型 'object' に変換できません。

ということを言いたいのだと思うのだが...

http://msdn.microsoft.com/ja-jp/library/hy74she2.aspx
の日本語は、

デリゲート型ではないため、匿名メソッド ブロックを型 '型' に変換できません

この日本語も変だ。
この原文は、
Cannot convert anonymous method block to type 'type' because it is not a delegate type

itを中途半端に省略しちゃったから変な日本語になってしまったんですね。


この記事へのコメント
ラムダ式は暗黙の(名前を指定しない)メソッド定義であってデリゲートオブジェクトのインスタンスの定義ではないからでしょう。デリゲートオブジェクト自体はSystem.Objectを継承とした由緒正しいオブジェクトです。

ラムダ式のメソッドとしてのシグネチャと(つまり引数とか返り値とか)と適合するデリゲート型をnewしてコンストラクタにラムダ式を渡すか、そのようなデリゲート型にキャストしてやるかのどちらかの手段をとって初めてデリゲートオブジェクトのインスタンスが手に入ります。
object a= new Func<int,int>((int _) => _ + 1);
object b =(Func<int, int>)((int _) => _ + 1);
これはどちらもコンパイラを通ります。キャストの文法は、普通キャストで新しいインスタンスは作られないので非合理的ですが、前者と等価な内容を持ちます。

なお、当該の箇所における問題はラムダ式あるいはメソッドがオブジェクトではない事という認識で間違いありません。ただし、ラムダ式あるいはメソッドをオブジェクトにする唯一の手段は適当なデリゲートオブジェクトのインスタンスを作る事なので件のエラーメッセージの表現になるのだと思います。

ちなみにデリゲートが要求される場面でラムダ式またはメソッドを直接渡す場合には型推論が働いて暗黙にラムダ式またはメソッドがデリゲートオブジェクトのインスタンスに変換されるみたいですよ。
EventHandler c=new EventHandler(myMethod);
EventHandler d=(EventHandler)myMethod;
EventHandler e=myMethod;
は全て通ります。よく、イベントに+=ラムダ式と直接書くのは三番目の書き方の応用ですが、本質的なのは一番目の書き方で、他のは全て一番目と等価な文法なのです。
Posted by tomorrowplusplus at 2009年01月20日 00:38
tomorrowplusplusさん

Expression に代入し、それをObjectに変換し、利用するときは、
objectを Expressionに変換し、Compileしないといけないのかと考え、そんな
面倒なことやめようと思ったのでした。
それに、ラムダ式で記述したかったのは、複数の文なので、よけいに面倒だなーと。
そうか、

object b =(Func<int, int>)((int _) => _ + 1);

こういった書き方ができるんですね。なんで試さなかったんだろう?
ラムダ式 → デリゲート への暗黙の変換があるんだから、
ラムダ式 → object とへの変換もできると思っていました。
「ラムダ式はデリゲートではないため」ってのは辻褄が合うわけですね。
ということで、この記事の後半の僕の指摘はおかしいですね。
ありがとうございます。


でも、object[](配列)に変換できませんってのはやはり変ですよね。
まあコンパイラのメッセージにそこまで求めても仕方ないか。
Posted by gushwell at 2009年01月20日 12:27
多分、ラムダ式(or メソッド)→デリゲートの変換はデリゲート型オブジェクトのインスタンスの生成なのに明示的/暗黙的キャストっぽく書けてしまうのでラムダ式自体が何らかのデリゲート型オブジェクトに思えてしまう混乱が生じるのでしょうね。

あと、そのメッセージは確かに変ですね。配列じゃないのはどっからどう見ても明らかだし、配列の要素に出来るかというのが問題なのだから。
Posted by tomorrowplusplus at 2009年01月20日 17:56
>ラムダ式自体が何らかのデリゲート型オブジェクトに思えてしまう混乱が生じるのでしょうね。

僕の混乱のもとは、まさしくこれですね(笑)
Posted by gushwell at 2009年01月20日 20:41
 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/51732971