2015-10-22 8 views
7

私は知識が必要な状況に遭遇しました。アクションはFunc <TResult>と同じですか?

// A function to match the delegate 
public static int DoSomething() 
{ 
    Console.WriteLine("i am called"); 
    return 1; 
} 

// Usage 
Action action =() => DoSomething(); 
Func<int> func =() => DoSomething(); 
action(); 
func(); 

Actionの私の理解では、それが何のパラメータを受け入れないし、何も返さないデリゲートを一致させる必要があることにするために使用:以下

はコードです。

Func<int>の場合、パラメーターを受け入れずにintを返すデリゲートと一致する必要があります。 () => DoSomething()intを返すデリゲートです:

DoSomething方法は、それゆえ私の質問は、整数を返します。 Funcは期待通りに機能しますが、Actionは機能しません。どうして?私はここで何が分からないのですか?

コードは正しくコンパイルされて実行され、両方とも出力i am calledです。私が知りたいことは、なぜAction action =() => DoSomething();はコンパイル時エラーではないのですか?

+3

* >>でもアクションはありません* - どのように動作しないのですか? –

+0

'Action action =(x)=> DoSomething(x);'というコードラインは、 'Action 'が値を返さないデリゲートと一致する必要があるため、コンパイル時エラーではないでしょうか? – singsuyash

+4

@singsuyash C#コンパイラは、 '(x)=> DoSomething(x)'は文脈に応じて異なることを理解するのに十分スマートです。それを使って 'Action'変数を割り当てると' Func'ではなく 'Action'が生成され、' DoSomething(x) 'の返り値は無視されます。 –

答えて

10

と等価である理由Action action =() => DoSomething();は、コンパイル時のエラーではないということでしょうか?

これは、メソッドを呼び出すラムダ式が得られたが結果は無視するためコンパイルされます。メソッドグループ変換は使用できませんでした。

// Compile-time failure 
// error CS0407: 'int Test.DoSomething()' has the wrong return type 
Action action = DoSomething; 

は(。Func<Action, int>に同じ方法でグループの変換は結構です)

しかし、その代わりに、あなたはより多くのこのような何かをやっている:

Action action = DoSomethingAndIgnoreResult; 
... 
private static void DoSomethingAndIgnoreResult() 
{ 
    DoSomething(); // Hey, I'm ignoring the result. That's fine... 
} 
+0

メソッドグループ変換のエラーは 'void DoSomething(object) 'シグネチャを持つメソッドが必要です@ –

+0

@DaveZych:完了実際のエラーメッセージが表示されます。 –

+0

更新された回答のための@JonSkeet :)ありがとうございます。将来このように変更しないように注意してください。 – singsuyash

3

C#コンパイラは、() => DoSomething()が文脈によって異なることを意味するのに十分にスマートです。それを使用してAction変数を割り当てると、DoSomething()の戻り値を無視するActionFunc<int>ではなく)が生成されます。

8

Action action =() => DoSomething();
Action action =() => { DoSomething(); };

Func<int> func =() => DoSomething();に相当し、私が知りたいのは何
Func<int> func =() => { return DoSomething(); };

0

すべてのあなたの理解が正しいです。混乱の原因となる可能性のある特定の使用法です。 FuncとActionの両方が問題ありません。両方の呼び出しはちょうどいいです。

var x = action(5); // NOT ok var y = func(5); // ok

あなたのサンプルコードは、ちょうど彼らが同じだようにそれはそうする理由である戻り値を、無視する:私はあなたの問題を照明することができる場合があると思います。 (x) => DoSomething(x)objectを受け入れ、intを返すデリゲートです:いいえ異なる

より

void Foo1(int x) { return; } void Foo2(int x) { return 1; } Foo1(5); Foo2(5);

1

DoSomething方法は、それゆえ私の質問は、整数を返します。Funcは期待通りに機能しますが、Actionは機能しません。どうして?私はここで何が分からないのですか?

あなたの理解の瑕疵はここにあります:(x) => DoSomething(x)にはタイプがありません。それは何もない。コンパイラは、これのタイプが何であるか把握するためにコンテキストを必要とします。ラムダは特別なものではないので、ラムダ式にはvarを使用できません。コンパイラはラムダの型を知らないので型を推論できません。例えば

(x) => DoSomething(x)も式ツリーのようになります。

Expression<Func<object, int>> e = (x) => DoSomething(x) 

だからあなたはあなたがそれを代入しているタイプに基づいて、ラムダを解釈する方法をコンパイラに指示しています。

関連する問題