4

このようなコードでは:

if (insuranceNumberSearch == null 
     ? true  
     : ei.InsuranceNumber.Contains(insuranceNumberSearch.Trim())) 
   doSomething();

どこinsuranceNumberSearchが null で、残りの式は次のコードでは null ではありません:

var q = from ei in session.Linq<EmployeeInsurance>()
        where insuranceNumberSearch == null 
                ? true 
                : ei.InsuranceNumber.Contains(insuranceNumberSearch.Trim())
        select ei;

式のすべてのセクションは、insuranceNumberSearch が null であるか、null でないかに関係なく評価されます。

LINQ to NHibernate を使用しています

アップデート:

残念ながら、最初のスニペットを間違えました。正しいのは次のとおりです。

if (insuranceNumberSearch == null || (insuranceNumberSearch != null && ei.InsuranceNumber.Contains(insuranceNumberSearch.Trim()))
doSomething();

また

bool b1 = insuranceNumberSearch == null ? true : ei.InsuranceNumber.Contains(insuranceNumberSearch.Trim());
if (b1)
doSomething();

上記の when insuranceNumberSearchisの両方でnull、残りの式はそれ以上評価されません。そのような動作が存在しない場合はinsuranceNumberSearch.Trim()参照オブジェクトが null例外になります。悲しいことに、LINQ (あるいは LINQ-to-NHibernate) は、このような優れた動作に従わず、すべての式を評価し、結果がエラーになる場合でもそうしませinsuranceNumberSearchnull

更新 2:同様の質問を見つけました: The || (または) C# を使用した Linq の演算子

4

3 に答える 3

5

私を打ち負かしますが、あなたは使わないでしょうか

if (
     (insuranceNumberSearch == null) ||
     ei.InsuranceNumber.Contains(insuranceNumberSearch.Trim()))
  doSomething();

あなたのステートメントでは、それがLINQ式であるかどうかに関係なく?

于 2010-02-21T15:22:21.510 に答える
3

このコードが示すように、これは LINQ の問題ではありません。このコードはあなたのものに似ていますが、LINQ 式の条件の両側を評価しません。

class Program
{
  class MyClass
  {
     public string value;
     public MyClass(string value) { this.value = value; }
     public bool Contains(char elem)
     {
        Console.WriteLine("Checking if {0} contains {1}", value, elem);
        return value.Contains(elem);
     }
  }

  static void Main(string[] args)
  {
     var mc = new MyClass[2];
     mc[0] = new MyClass("One");
     mc[1] = new MyClass(null);
     var q = from i in mc where i.value == null ? true : i.Contains('O') select i;
     foreach (MyClass c in q)
        Console.WriteLine(c.value == null ? "null" : c.value);
  }
}

LINQ to NHibernate の式エバリュエーターは、LINQ to Objects のようにショットカット条件付き操作を実行しない可能性があります。

プログラムの出力は次のとおりです。

Checking if One contains O
One
null

LINQ は、他の構文に変換するための任意の式を表す方法であることに注意してください。私が理解しているように、LINQ自体は式を評価せず、NHibernateは(それが何であれ)評価します。そのため、LINQ は指定した式を NHibernate と互換性のある式に変換するだけです。NHibernate にショートカットの条件付き操作を表す手段がない場合、次の 3 つのいずれかが発生すると想像できます。

  1. NHibernate は独自の方法で式を評価します (VB.NET の非ショートカット AND 演算子を使用した場合でも、LINQ to SQL が常に AND 操作をショートカットするように)。
  2. 式を NHibernate 構文で表現できないというエラーが表示されます。
  3. クエリの限られた部分のみが NHibernate 構文に変換されます。残りは LINQ to Objects によって評価されます。
于 2010-02-21T15:35:47.840 に答える
2

問題は LINQ の NHibernate プロバイダーにあるようです - オブジェクトへの LINQ の場合 (クエリからメソッド呼び出しへの単純な構文変換を行うだけです)、法則は期待どおりに保持されます。問題は、式ツリーを使用する場合、プロバイダーがコードを変更できることです。

さらに悪いことに、ターゲットの実行環境は、一部の C# 操作の正確なセマンティクスをサポートしていない可能性があります。たとえば、浮動小数点演算の実装が同じではない場合があります。

あなたの例では、NHibernate は短絡動作をサポートしていないようです。なぜそれが問題になるのかは私には明らかではありません.式の2番目の部分を評価することはできますが、結果は同じになるはずです.

とにかく、短絡演算子がプロバイダーに問題を引き起こす場合は、おそらくクエリを 2 つに分割する必要があります。

var q = 
  insuranceNumberSearch == null 
    ? session.Linq<EmployeeInsurance>() 
    : (from ei in session.Linq<EmployeeInsurance>() 
       where ei.InsuranceNumber.Contains(insuranceNumberSearch.Trim()) 
       select ei); 
于 2010-02-21T16:21:08.903 に答える