2017-08-03 11 views
1

私はlinq .Where()呼び出しのラムダ内で無名関数を使用するための構文を試してみようとしています。ラムダ内のC#匿名関数

私はリストから特定の項目をフィルタリングする場所を使用しています。

フィルタロジックの各部分をWhere内部に入れたいと思います。ロジックはフィルタ内でのみ有効なので、外部の関数を定義する必要はありません。ここで

は、簡略化さ&一般化した例です:

var filtered = myEnumerable.Where(item => 
    item.PropertyA == 1 || 
    item.PropertyB == 2 || 
    item => 
    { 
     var heavyResult = GetStuff(item); // Some heavyweight processing 
     return heavyResult.IsSomethingTrue() && heavyResult.IsSomethingElseTrue(); 
    }); 

は、だから私は(どこで三行目をしたい)匿名関数の項目を取り、ブール値を返すように。

また、PropertyAおよびPropertyBのチェックの後に呼び出される関数は、いずれかの軽量比較が既にtrueと評価されている場合にGetStuff()を呼び出す必要を制限することを目的としています。

heavyResultから2つのプロパティを評価する必要があるため、すべてインラインで行うことはできません。

これは単純なはずですが、実験やグーグルで正しい構文を見つけることができないようです。

+0

私はこれが本当のシナリオがあるかどうかを実際に懐疑的:

次のコードで

、あなたはここで完全なコードです

validator(item) || GetStuff(item).IsAllTrue() || GetStuff(item).IsAllTrueExt() 

からのオプションのうち1つだけを使用するのでしょうか?あなたはもっと簡単な方法でそれを行うことができます –

+0

これを行うことができますが、私はあなたが*すべきなのは疑います。代わりに、そのメソッド内で何が起こるかを識別するためのわかりやすい名前を持つ名前付きメソッドを抽出するだけです。 – HimBromBeere

答えて

2

heavyResultから2つのプロパティを評価する必要があるため、すべてインラインで行うことはできません。

あなたはインラインそれを行うことができ、そのちょうどあなたが{}で全体の事をラップし、returnキーワードを使用する必要があります。

var filtered = myEnumerable.Where(item => 
    { 
     var test = item.PropertyA == 1 || item.PropertyB == 2; 
     if(test) 
      return true; 
     var heavyResult = GetStuff(item); // Some heavyweight processing 
     return heavyResult.IsSomethingTrue() && heavyResult.IsSomethingElseTrue(); 
    }); 

正直言っても、単純なインラインであってもおそらく間違った選択です。意味のある名前で、機能にそれを解凍して、あなたのコードは、自己

まず
var filtered = myEnumerable.Where(ADescriptiveNamedFunctionSelfDocumentsYourCode); 
+0

ありがとうございます。私はこのスタイルで作業しました。 PropertyAとPropertyBのチェックのために私には醜いだけです。 GetStuff/heavyResultの部分を無名関数にバンドルする方法があるはずです。 – Tom

+0

@Tom - あります。それはこの答えです。 – Jamiec

+0

ありがとうございます。私はそのようにしようとするべきかどうかについてのコメントを感謝しています。実際の例では、フィルタリングロジックを実行するための外部メソッドを定義する必要があります。 上記の私の特定の質問に関しては、純粋に構文的に言えば、私はその答えは - いいえ、似たような匿名関数を定義する方法はないと思いますか? – Tom

0

を文書で、複数行のラムダは本当に悪い考えです。

これらは単純な機能表現f(x)= ...ものとして意図されていました。

最初に関数を呼び出してその結果をキャプチャしたいので、&を呼び出し、そのオブジェクトに対して2つの異なるメソッドを呼び出すので、これを行うことはできません。

これを行うには、デリゲートをラムダから移動するだけです。

最新バージョンのC#は、ローカル関数をサポートしています。しかし、C#6の無名関数でもこれを行うことができます。HeavyResultまたは別の方法でこれを行う方法や拡張方法は、HeavyResultを変更することができません。

public static class Program 
{ 
    static void Main(string[] args) 
    { 
     var myEnumerable = new List<int>() { 1, 2, 3, 4, 5 }; 

     Predicate<int> validator; 
     validator = delegate (int item) 
     { 
      var heavyResult = GetStuff(item); 
      return heavyResult.IsSomethingTrue() && heavyResult.IsSomethingElseTrue(); 
     }; 

     var filtered = myEnumerable.Where(item => 
     item >= 1 || 
     item <= 200 || 
     validator(item) || 
     GetStuff(item).IsAllTrue() || 
     GetStuff(item).IsAllTrueExt() 
     ); 
    } 

    public static bool IsAllTrueExt(this HeavyResult hr) 
    { 
     { return hr.IsSomethingTrue() && hr.IsSomethingElseTrue(); } 
    } 

    public static HeavyResult GetStuff(int item) 
    { 
     return new HeavyResult(item); 
    } 

    public class HeavyResult 
    { 
     public HeavyResult(int value) 
     { 
      Value = value; 
     } 

     int Value { get; } 

     public bool IsSomethingTrue() 
     { 
      { return Value >= 5; } 
     } 

     public bool IsSomethingElseTrue() 
     { 
      { return Value <= 50; } 
     } 

     public bool IsAllTrue() 
     { 
      { return IsSomethingTrue() && IsSomethingElseTrue(); } 
     } 

    } 
}