c# - 最后添加 .ToList(或 ToArray)时出现 LINQ 'OR' 条件问题

标签 c# sql-server linq asp-classic lambda

通过 DataContext 使用数据库。

有这样的操作:

var flat = StavRealtyDb.TargetFlat
    .Where(x => true || _some condition_).ToList();

因此,如果条件的第一部分为true,则编译器应该跳过第二部分,对吧? 但这并没有发生。如果有.ToArray(),也会发生同样的问题。

但是,如果最终不是 .ToList 或 .ToArray 之类的内容 - 编译器将跳过条件的第二部分。

有什么问题吗?正常吗? :)

更新

好的,谢谢您的解答!我明白这是正常的。但问题是条件的第一部分包含: someobject == null;第二部分包含:someobject.Contains()。

.Where(x => someobject == null || someobject.Field.Contains(x.somefield))

所以当 someobject == null 时我有 ArgumentNullException (我希望第一部分将返回 true 而第二部分将不会执行)。你能告诉我,我该如何解决这个问题吗?

P.S:实际上,.Where() 表达式更复杂:

.Where(x=> (part1 || part 2) && (part1 || part2) && ......)

最佳答案

您正在 IQueryable 上执行 Where,并且参数是 Expression 而不是 Func

http://msdn.microsoft.com/en-us/library/vstudio/bb535040%28v=vs.100%29.aspx

Expression 只是传递给底层 Where 实现。

我发现这个主题很有趣,所以我创建了一个示例。假设我们有以下代码:

using System;
using System.Linq.Expressions;

namespace TestApplication
{
    class CompilerTest
    {
        public void Test()
        {
            Func<bool> func = () => true || Foo();
            Expression<Func<bool>> expr = () => true || Foo();
        }

        public static bool Foo()
        {
            return new Random().Next() % 2 == 0;
        }
    }
}

我们构建它(发布构建),反编译的代码如下所示:

using System;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;

namespace TestApplication
{
  internal class CompilerTest
  {
    [CompilerGenerated]
    private static Func<bool> CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate1;

    public CompilerTest()
    {
      base.\u002Ector();
    }

    public void Test()
    {
      if (CompilerTest.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate1 == null)
      {
        // ISSUE: method pointer
        CompilerTest.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate1 = new Func<bool>((object) null, __methodptr(\u003CTest\u003Eb__0));
      }
      Func<bool> func = CompilerTest.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate1;
      (Expression<Func<bool>>) (() => true || CompilerTest.Foo());
    }

    public static bool Foo()
    {
      return new Random().Next() % 2 == 0;
    }

    [CompilerGenerated]
    private static bool \u003CTest\u003Eb__0()
    {
      return true;
    }
  }
}

如果我们隐藏编译器生成的代码(dotPeek 选项),它看起来像这样:

using System;
using System.Linq.Expressions;
namespace TestApplication
{
  internal class CompilerTest
  {
    public void Test()
    {
      Func<bool> func = (Func<bool>) (() => true);
      (Expression<Func<bool>>) (() => true || CompilerTest.Foo());
    }

    public static bool Foo()
    {
      return new Random().Next() % 2 == 0;
    }
  }
}

正如我们所看到的,lambda 中指定的 Func 代码已被优化(如果编译器对其进行了优化,这才是真正的问题)。表达式中指定的代码显然没有优化(因为它是一个表达式,所以从编译器的角度来看,此时没有什么可以优化的)。

关于c# - 最后添加 .ToList(或 ToArray)时出现 LINQ 'OR' 条件问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27514427/

相关文章:

c# - 从 C# 中生成的搜索结果中选择一个随机链接

c# - InvalidOperationException : Cannot resolve scoped service 'Microsoft. AspNetCore.Identity.UserManager .NET 核心 2.0

c# - ProgressBar 更新期间 UI 卡住

c# - 如何反序列化自定义对象列表

sql-server - Oracle 的 SYS_CONTEXT 的 PostgreSQL 和/或 SQL Server 替代品

SQL 如何编写返回缺失日期范围的查询?

c# - 无参数构造函数

sql-server - SQL 类命令中的 IP 地址模式

c# - LINQ:当连接表中的计数为零时列出所有

c# - LINQ 查询合并多行