2009-10-20 15 views
21

を受け入れる方法を書く:私は次のシグネチャを持つメソッドいるラムダ式

MyMethod((int a) => a) 

を次のエラーで:しかし、これはコンパイルする

void MyMethod(Delegate d){}; 
void MyMethod(Expression exp){}; 
void MyMethod(object obj){}; 

を失敗し

"Cannot convert lambda expression to type 'object' because it is not a delegate type" 

なぜこれは機能しませんか?

編集:私はこれが動作することを知っています。この場合、コンパイラはラムダ式をコンパイルしてコンパイルします。

void MyMethod(Func<int, int> d){}; 

敬具、使用中の

+3

Fyi、何かがコンパイルに失敗したときはいつも、エラーメッセージも読んで(そして投稿する)。 –

+0

@SharePoint初心者:最新の投稿をご覧ください。それはあなたのエラーを今すぐ解決するはずです。 – Noldorin

答えて

17

System.Delegate型が「代理人」ではないためです。それは単なる基本クラスです。正しいシグネチャを持つデリゲート型を使用する必要があります。次のようにあなたの方法を定義します。

void MyMethod(Func<int, int> objFunc) 

EDIT:ラムダ式は、それ自身では何の種類を持っていませんが、種類は場所の種類から推測されるので、

MyMethodは(オブジェクト)が動作しないことに割り当てられます。したがって、オブジェクトはどちらも機能しません。正しいシグネチャを持つデリゲート型を使用する必要があります。

+0

私はこれが動作することを知っています、私はなぜ他の署名が機能しないのか知りたいです。 –

+0

その後、私が書いたものを読んでください。 System.Delegateはデリゲートではなく、ラムダ式はSystem.Delegateに変換できません。実際には、ラムダ式は型自体を持たず、割り当てられた変数の型から型を取得するので、objectも機能しません。 –

+0

しかし、自分でタイプを指定しています。それは暗黙のうちに推論されていません、 "(int a)=> a;"。ラムダ式に型がないことを説明してください。 –

12
void MyMethod(Action<int> lambdaHereLol) 
{ 
    lambdaHereLol(2); 
} 

var hurrDurr = 5; 
MyMethod(x => Console.Write(x * hurrDurr)); 

C#は静的に型付けされた言語です。コンパイラは、扱うすべての型を知る必要があります。 Lambdasは少し難しく、コンパイラはそれを理解できないことがあります。上記の例では、MyMethodがオブジェクトを取得した場合、コンパイラはxintであることを認識できませんでした(私の例は単純ですが、はるかに複雑で難しいとは言いません)。だから私はラムダを取る方法を定義する上でより明示的にする必要があります。

+1

他の人はいつも「クロチュア」と「クロージャー」をミックスしていますか? – Will

+3

トロルコーダーセマンティクスのための+1 – Filip

+1

"C#は静的型言語です。コンパイラは扱うすべての型を知る必要があります。"これは本当ですが、残りは従いません。あなたのために型署名を推論できる静的型付き言語がたくさんあります。 F#は一例です。 – rgrinberg

2

これを試してください:あなたはメソッドのパラメータとして強く型付けされたデリゲートに必要

void MyMethod(Action<int> func) { } 

。他の呼び出しが失敗する理由は、C#コンパイラはラムダ式がObjectを予期しているメソッドにラムダ式を渡すことを許可しないためです。ラムダ式は常にすべての場合においてデリゲートであるとは限りません。この同じルールは、ラムダ式をDelegateとして渡す場合に適用されます。

上記に示したような関数にラムダを渡すと、ラムダ式を特定のデリゲート型に変換して欲しいとコンパイルできます。

+0

私はこれが動作することを知っています、私はなぜ他の署名が機能しないのか知りたいです。 –

0

代理オブジェクトをDelegateに明示的にキャストする必要があるのは、Delegateのパラメータとして渡すときだけです。実際、ラムダ式は、この場合、代理人に暗黙的に変換できないという点で、さらに複雑になります。

あなたが必要とするようなダブルキャスト、次のとおりです。

、あなたの状況に応じて
void MyMethod(Delegate d); 

、あなたはパラメータを定義することもできます。メソッドのシグネチャに対応し、もちろん

MyMethod((Delegate)(Func<int, int>)((int a) => a)); 

DelegateではなくFunc<int>のタイプです(ただし、正当性が不必要に複雑になるため、過負荷を追加することは躊躇します)。

+0

これも機能しません。 –

+0

ええ、私が書いたように、System.Delegateはデリゲートではありません。デリゲートの基本型です。 –

+1

Woops、そうです。私は最初に発生する必要があるデリゲート型への変換を逃しました。この種のことは、C#コンパイラがラムダ式をデリゲートに暗黙的に変換する方法と、それをパラメータとして渡す方法についての洞察を提供します。ここで見ていることは、すべて「手動で」行うことです。 – Noldorin

3

ラムダ(int a) => aは、intを受け取り、intを返すデリゲートに適合します。 Func<int,int>は単なる例に過ぎず、delegate int Foo(int x);で自分自身を簡単に宣言することができます。実際には、このラムダ式は、intを受け取り、ラムダ(a)の結果がdoubleに暗黙的に変換されるため、doubleを返すデリゲートに適合します。

ラムダが適合するすべてのデリゲート型にラムダを割り当てることができるように、ラムダ自体には型がありません。代わりに、可能であれば、それを使用している代理人のタイプを取ります。 ((int a) => aはもちろんのFunc<byte, byte>に割り当てることができません。)

Func<int, int>と私はそれが何をその実際は不明であるため、ラムダが直接Delegateに変換することができない、当然の缶はDelegateに変換され定義されたFooデリゲートの両方ながら署名はその後になります。 Delegate d = (int a) => aの後、dFoo、またはFunc<int, int>、さらにはFunc<int, double>?すべてが有効な可能性があり、コンパイラはあなたが意図したことを全く知らない。それは最高の推測をすることができますが、C#はそのような推測を行う言語のようなものではありません。これはまた、あなたがvar = (int a) => aのような何かをすることができない理由です。

私は、コンパイラがDelegate d = (int a) => a;のために与えることをエラーメッセージが非常に不明瞭であると思います:

Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type

直感的にあなたはDelegateは、デリゲート型であると思うだろうが、それは物事の仕組みではありません。 :)

0

これが失敗する理由は、「object del =(int a)=> a」や「var del =(int a)=> a」などの式も失敗するのと同じ理由です。あなたは明示的に引数の型を与えているのでコンパイラはラムダ式の型を知ることができると思うかもしれませんが、式がintをとりintを返すことさえ知っていても、に。 Funcデリゲート型は、このような汎用関数で最もよく使用される型ですが、これは単なる規約であり、コンパイラは認識していません。

通常のキャスト構文(Func)((int a)=> a)を使用して、コンパイラにデリゲートのオーバーロードを選択させるために、ラムダ式を具体的なデリゲート型にキャストする必要があります。代理コンストラクタの構文new Func((int a)=> a)を使用します。

また、受け入れる引数の数に応じて別のものを呼び出す必要がない限り、型指定されていないDelegateクラスを使用することは通常ありません。コールバックのようなものに対しては、FuncやActionを受け入れるほうがずっと良いです。

関連する問題