c# - ラムダ式とプライベートメソッドの使用




.net lambda (7)

スタックオーバーフローに関する質問には、次のようなコードが含まれています。

Action<Exception> logAndEat = ex => 
{  
    // Log Error and eat it
};

try
{
    // Call to a WebService
}
catch (SoapException ex)
{
    logAndEat(ex);
}
catch (HttpException ex)
{
    logAndEat(ex);
}
catch (WebException ex)
{
    logAndEat(ex);
}

私の質問は、(私の見解ではもっと簡単で明白な)プライベートメソッドとは対照的に、LogAndEatのラムダ式を以下のように使用することの利点は何ですか:

private void LogAndEat(Exception ex)
{
    // Log Error and eat it
}

編集:これまでの回答をありがとうが、ちょうど私の根本的な質問をもう少し明確に再:どのアプローチが良いですか、このインスタンスでお勧めですか? ラムダ式またはプライベートメソッド?


Answers

皆さん、ありがとうございました。投票した偉大な回答をお寄せいただきましたが、賛否両論を1つの答えに取り入れるように要約したと思いました。

プライベートメソッドの代わりにラムダ式(LE)を使用する利点:

  • LEは宣言されているメソッドにスコープが設定されているため、そのメソッドでのみ使用されている場合は、ラムダ式でその意図が明示されます(LEにデリゲートを渡すことは可能ですが、メソッドでLEを宣言する意図は、LEがそのメソッドにスコープされていることです)。 つまり、期待される使用法の観点から明白です。
  • ラムダ式はクロージャのように振舞い、宣言されたメソッドにスコープされた変数にアクセスすることができます。これは、プライベートメソッドに多くのパラメータを渡すよりも簡単です。
  • LEによって捕捉された変数は、さもなければプライベートメソッドへのパラメータとなり、カリングの形式を可能にするためにこれを利用することができます。

プライベートメソッドの代わりにラムダ式を使うことの短所:

  • LEは、それらが含まれているメソッドにスコープされた変数にアクセスできるため、デバッグ中に呼び出しメソッド内のコードを変更することはできません。

メンテナンス性の主観的な問題もあり、LEはほとんどの開発者によって私的な方法としてよく理解されておらず、したがって保守性はやや劣ると主張することができます。 LEはクラス全体に見えるプライベートメソッドとは対照的に呼び出されるメソッドにカプセル化されているため、LEはメンテナンス性を向上させると主張することもできます。


この例のラムダ式は、宣言されたメソッドでしか実行できないコードであるという点で、Pascalのネストされた関数に少し似ていると考えることができます。

プライベートメソッドは同じクラスの任意のメソッドから呼び出すことができますが、このようなラムダは現在のメソッドに対してローカルなので、そのコンテキストでのみ明示的に使用されます。

これは、私が考えることができる唯一の利点です。期待される使用法に関して明白です。


IMO私は私のクラスの周りに疑問に思っている別のプライベートメソッドでのみ使用される小さな小さなプライベート関数を好きではありません。私はそれらが醜いと思うので、そのサンプルでラムダを使用します

私は関数の代わりにラムダを使用するとパフォーマンスに影響が出るとは思わない


多くは個人的な好みになり、誰も絶対的な方法は正しい方法か間違った方法であると言うことはできません。

ラムダ式は他の言語のクロージャのように振る舞いますが、宣言されたメソッドの変数にアクセスできるという点で優れています。これにより、コード内でできることに柔軟性が増しますが、コストはかかりますデバッグ中にそのメソッドのコードを変更できないという問題がありました。

そのため、エラーをログに記録する場合は、ある時点でそのメソッドのデバッガに自分自身が存在する可能性があります。 ラムダを使用する場合は、実行時にコードを変更することはできません。そのため、私の好みは、パラメータとして例外を受け入れる別のプライベートメソッドを使用することです。


logAndEatによってlogAndEatされた変数は、そうでなければLogAndEatメソッドのパラメータになります。 あなたはカレーの一種と考えることができます。


LogAndEatは、定義されている関数内のプライベートフィールドを参照できます。 そう:

private bool caughtException; 

Action<Exception> logAndEat = ex => 
    {  
        caughtException = true;
    };

try
{
    // Call to a WebService
}
catch (SoapException ex)
{
    logAndEat(ex);
}
catch (HttpException ex)
{
    logAndEat(ex);
}
catch (WebException ex)
{
    logAndEat(ex);
}

if (caughtException)
{
    Console.Writeline("Ma, I caught an exception!");
}

これは漠然とした例です(!)が、これはプライベートメソッドに一連のパラメータを渡すよりも、潜在的に非常に細かいことがあります。


アンサー

Q:C ++ 11のラムダ式とは何ですか?

A:フードの下では、 operator()constのオーバーロードを伴う自動生成されたクラスのオブジェクトです。 このようなオブジェクトはクロージャと呼ばれ、コンパイラによって作成されます。 この「クロージャ」コンセプトは、C ++ 11のバインドコンセプトに近いものです。 しかし、ラムダは通常、より良いコードを生成します。 また、クロージャを介したコールにより、完全なインライン化が可能になります。

Q:いつ使うのですか?

A: "単純で小さなロジック"を定義し、コンパイラに前の質問からの生成を依頼する。 あなたはoperator()の中に入れたいいくつかの式をコンパイラに与えます。 他のすべてのstuffコンパイラが生成します。

Q:彼らはどのようなクラスの問題を解決しているのですか?

A:これは、カスタムの追加、サブタスク操作のための関数の代わりに演算子のオーバーロードのような構文砂糖のようなものです...しかし、不要なコードの行を節約して、実際のロジックを1-3行にまとめることができます。 一部のエンジニアは、ラインの数が少ない場合はエラーが発生する可能性が低いと考えている(私もそうだと思う)

使用例

auto x = [=](int arg1){printf("%i", arg1); };
void(*f)(int) = x;
f(1);
x(1);

質問で覆われていないラムダについてのエクストラ。 あなたが興味がないなら、このセクションを無視してください

1.キャプチャされた値。 キャプチャすることができるもの

1.1。 ラムダで静的な記憶期間を持つ変数を参照することができます。 彼らはすべて捕獲されます。

1.2。 キャプチャ値を "値"としてラムダを使うことができます。 そのような場合、キャプチャされた変数は関数オブジェクト(クロージャ)にコピーされます。

[captureVar1,captureVar2](int arg1){}

1.3。 あなたは参考になることができます。 & - この文脈では、ポインタではなく参照を意味します。

   [&captureVar1,&captureVar2](int arg1){}

1.4。 すべての非静的変数を値または参照によって取得する表記法があります

  [=](int arg1){} // capture all not-static vars by value

  [&](int arg1){} // capture all not-static vars by reference

1.5。 すべての非静的変数を値で取得するか、または参照してスムースを指定する表記法があります。 もっと。 例:静的でないすべての変数を値でキャプチャするが、参照キャプチャではParam2

[=,&Param2](int arg1){} 

静的でないすべての変数を参照でキャプチャするが、値キャプチャではParam2

[&,Param2](int arg1){} 

2.返品タイプ控除

2.1。 ラムダが1つの式である場合、ラムダの戻り値の型が導かれます。 あるいは明示的に指定することもできます。

[=](int arg1)->trailing_return_type{return trailing_return_type();}

lambdaに複数の式がある場合、戻り型は後続の戻り型で指定する必要があります。 また、同様の構文を自動関数とメンバ関数に適用できます

3.キャプチャされた値。 キャプチャできないもの

3.1。 オブジェクトのメンバ変数ではなく、ローカル変数だけをキャプチャできます。

4.コンバージョン

4.1 !! Lambdaは関数ポインタではなく、無名関数ではありませんが、 キャプチャレスの lambdaは暗黙的に関数ポインタに変換できます。

ps

  1. ラムダの詳細文法情報は、Programming Language C ++#337、2012-01-16、5.1.2のWorking Draftにあります。 ラムダ式、p.88

  2. C ++ 14では、「init capture」という名前の追加機能が追加されました。 クロージャーデータメンバーの宣言を任意に実行することができます。

    auto toFloat = [](int value) { return float(value);};
    auto interpolate = [min = toFloat(0), max = toFloat(255)](int value)->float { return (value - min) / (max - min);};
    




c# .net lambda