web-dev-qa-db-ja.com

new Action()とラムダの違いは何ですか?

だから私がこのようなものを書くとき

Action action = new Action(()=>_myMessage = "hello");

プロのリファクタリング!これを冗長なデリゲート作成として強調し、短縮して

Action action = () => _myMessage="hello";

そして、これは通常うまくいきます。 通常、ただし常にではありません。たとえば、Rhino MocksにはDoという名前の拡張メソッドがあります。

IMethodOptions<T> Do(Delegate action);

ここでは、最初のバージョンを渡すと機能しますが、2番目のバージョンは機能しません。ここで何が起こっているのですか?

41
George Mauer

最初のバージョンは効果的にやっています:

Action tmp = () => _myMessage = "hello";
var action = new Action(tmp);

あなたが遭遇している問題は、コンパイラがラムダ式をどのようなデリゲート(または式ツリー)に変換する必要があるかを知っている必要があることです。これが理由です:

var action = () => _myMessage="hello";

実際にはコンパイルされません-それはanyデリゲート型で、パラメーターがなく、戻り値がないか、_myMessageと同じ戻り値型(おそらくstring)です。たとえば、次のすべてが有効です。

Action action = () => _myMessage="hello";
Func<string> action = () => _myMessage="hello";
MethodInvoker action = () => _myMessage="hello";
Expression<Action> = () => _myMessage="hello";
// etc

actionで宣言された場合、C#コンパイラはどのような型のvarが意図されていたのかをどのように確認できますか?

メソッドを呼び出すときにこれを回避する最も簡単な方法(Rhino Mocksの例の場合)は、キャストすることです。

methodOptions.Do((Action) (() => _myMessage = "hello"));
60
Jon Skeet

2行目が実際にコンパイルされることを確認しましたか? C#は暗黙的に型指定された変数へのラムダ式の割り当てをサポートしていないため、コンパイルしないでください(CS0815)。この行は、匿名のデリゲート作成をサポートしているため、VB.Netで機能します(VB 9.0以降))。

Rhino Mocksバージョンは、2行目がコンパイルされるべきではないのと同じ理由でコンパイルされません。 C#はラムダ式の型を自動的に推測しません。ラムダ式は、デリゲートタイプが満たすことを意図して決定できるコンテキストで使用する必要があります。最初の行は、意図したタイプが明確であるため、うまく機能します:アクション。デリゲートは抽象デリゲートタイプに似ているため、Rhino Mocksバージョンは機能しません。 ActionやFuncなどの具体的なデリゲート型である必要があります。

このトピックの詳細については、次の件に関するEric Lippertのブログエントリを参照してください。 http://blogs.msdn.com/ericlippert/archive/2007/01/11/lambda-expressions-vs-anonymous -methods-part-two.aspx

9
JaredPar

アクションは特別なタイプのデリゲートです。したがって、ラムダを使用する場合、多くの(Action、Func、...)があるため、どのタイプを使用するかを理解できません。

このキャストの必要性を克服するには(ほとんどの場合に遅い)基本関数のパラメーターをDelegateからActionに変更できます。

IMethodOptions<T> Do(Action action);

このようにして、両方のステートメントを使用でき、何の違いもありません。

Action action = new Action(()=>_myMessage = "hello"); 
Action action = () => _myMessage="hello";

これが不可能な場合は、キャストする代わりにnew Action(()=> {})を使用することをお勧めします。

アクションとデリゲートの詳細については、次のリンクを参照してください。 https://docs.Microsoft.com/en-gb/dotnet/api/system.action?view=netframework-4.7.1#definition =

1
Avjol Sakaj