4

在这样的代码中:

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

其中insuranceNumberSearch为空,在以下代码中剩余的表达式不为空:

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()将导致引用对象为空异常。可悲的是 LINQ(或者可能是 LINQ-to-NHibernate)不遵守如此好的行为并评估所有表达式,即使insuranceNumberSearchnull并且导致错误。

更新2:我发现了一个类似的问题:|| (或)使用 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 没有表示快捷条件操作的方法,我可以想象会发生以下三件事之一:

  1. NHibernate 将以自己的方式评估表达式(就像 LINQ to SQL 将始终使用快捷方式 AND 操作,即使您使用 VB.NET 中的非快捷方式 AND 运算符)。
  2. 您将收到一个错误,即表达式无法用 NHibernate 语法表示。
  3. 只有有限的部分查询会被转换为 NHibernate 语法;其余的将由 LINQ to Objects 评估。
于 2010-02-21T15:35:47.840 回答
2

似乎问题出在 LINQ 的 NHibernate 提供程序中 - 对于 LINQ 到对象(它只是将查询转换为方法调用的简单语法转换),法律将按预期成立。问题是在使用表达式树时,提供者可以对您的代码进行任何修改。

更糟糕的是——目标执行环境可能不支持某些 C# 操作的确切语义。例如,它可能没有相同的浮点运算实现。

在您的示例中,NHibernate 似乎不支持短路行为。我不清楚为什么这会是一个问题 - 它可以评估表达式的第二部分,但结果应该是相同的。

无论如何,如果短路运算符给提供者带来问题,您可能需要将查询分成两部分:

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 回答