为什么我没有收到空引用异常?

我正在使用 LINQ to Entities 从数据库中获取一些数据。以下是我的查询。


var location = from l in dbContext.Locations

join e in dbContext.Equipment on l.ID equals e.LocationID into rs1

from e in rs1.DefaultIfEmpty()

where ids.Contains(l.ID)

select new

{

    EquipmentClass = e,

    LocationID = l.ID,

    LocationName = l.Name,

    EquipmentName = e == null ? null : e.Name,

    Description = e == null ? null : e.Description,

    InServiceStatus = e == null ? false : e.InServiceStatus,

    EquipmentType = e.EquipmentType.Name

};


foreach (var item in location)

{

    // some logic

}

在上面的代码中,ids是我传入以过滤结果的整数列表。当我得到结果时,我看到其中一个返回记录有一个 null EquipmentClass。我执行了一些空值检查,但意识到我忘记对其中一个属性进行空值检查。现在我希望得到一个空引用异常,EquipmentType = e.EquipmentType.Name但我没有。令我惊讶的是,它工作得很好,并且设置为 null。MyEquipmentClass的属性类型为EquipmentType,这是另一个类。EquipmentType有一个Name属性,它是一个字符串。

  1. 为什么这不会引发空引用异常?

就像测试一样,我从中删除了空检查,InServiceStatus = e == null ? false : e.InServiceStatus并在使用查询运行 foreach 循环时失败并出现无效操作异常。

  1. 这是否意味着我只需要对不可为空的值进行空检查?


Cats萌萌
浏览 108回答 3
3回答

MYYA

如果您针对 编写 LINQ 查询IQueryable,会发生什么情况是您在后台调用的方法(例如Select、Where等)除了记录您如何调用它们之外没有做任何其他事情,即它们记录谓词表达式并继承一个 LINQ 提供程序。一旦您开始迭代查询,就会要求提供者执行查询模型。所以基本上,提供者使用表达式模型为您提供预期类型的结果。提供者绝不需要实际编译甚至执行您作为表达式交付的代码(模型)。事实上,LINQ to SQL 或 LINQ to Entities 的全部意义在于提供程序不这样做,而是将代码表达式转换为 SQL。因此,您的查询实际上被呈现为 SQL 查询,并且该查询的结果被翻译回来。因此,您在查询中看到的变量e不一定是真正创建的,而只是用于 LINQ 提供程序来编译 SQL 查询。但是,大多数数据库服务器都有空传播。对 LINQ to Objects 运行相同的查询,您将得到缺少的 NullReferenceException。

慕尼黑5688855

您的更新帮助我了解了您真正关心的问题。关于 LINQ 查询,您需要了解的概念是 LINQ 中的延迟执行。请通过以下链接了解更多详情:LINQ 中的延迟执行有什么好处?Linq - 找出延迟执行的最快方法是什么?现在你的情况会怎样?您已将查询存储在location变量中。该特定步骤只是初始化部分。它并没有真正通过您的 ORM 层对您的数据库执行查询。这就是您可以测试的方式。location在使用 LINQ 查询初始化变量的代码行上放置一个断点。当调试器在 Visual Studio 中停止时,请转到 SQL Server Management Studio (SSMS) 并启动 SQL Server Profiler 会话。现在在 Visual Studio 中按下F10以跳过代码语句。此时,您将在分析器会话中看到绝对没有查询执行,如下所示:这都是因为 LINQ 查询直到此时才被执行。现在您可以访问以下代码行:foreach (var item in location){&nbsp; &nbsp; var p = item.EquipmentClass.EquipmentType.Name;}在您进入 foreach 循环的那一刻,LINQ 查询被触发,您将在 SQL Server 探查器中看到相应的登录跟踪会话。因此,除非枚举 LINQ 查询,否则它不会被触发。这称为延迟执行,即运行时延迟执行直到枚举。如果您从未location在代码中枚举变量,那么查询执行将永远不会发生。因此,要回答您的查询,只有在查询被触发时才会出现异常。不是在那之前!更新 1:您是说 -我没有得到空引用异常。是的!在您到达缺少相应 RHS 加入记录的记录之前,您不会得到空引用异常。请查看以下代码以更好地理解:class Program{&nbsp; &nbsp; static void Main(string[] args)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var mylist1 = new List<MyClass1>();&nbsp; &nbsp; &nbsp; &nbsp; mylist1.Add(new MyClass1 { id = 1, Name1 = "1" });&nbsp; &nbsp; &nbsp; &nbsp; mylist1.Add(new MyClass1 { id = 2, Name1 = "2" });&nbsp; &nbsp; &nbsp; &nbsp; var mylist2 = new List<MyClass2>();&nbsp; &nbsp; &nbsp; &nbsp; mylist2.Add(new MyClass2 { id = 1, Name2 = "1" });&nbsp; &nbsp; &nbsp; &nbsp; var location = from l in mylist1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;join e in mylist2 on l.id equals e.id into rs1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;from e in rs1.DefaultIfEmpty()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//where ids.Contains(l.ID)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;select new&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;EquipmentClass = e,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;InServiceStatus = e == null ? 1 : e.id,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;EquipmentType = e.id&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;};&nbsp; &nbsp; &nbsp; &nbsp; foreach (var item in location)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}class MyClass1{&nbsp; &nbsp; public int id { get; set; }&nbsp; &nbsp; public string Name1 { get; set; }}class MyClass2{&nbsp; &nbsp; public int id { get; set; }&nbsp; &nbsp; public string Name2 { get; set; }}所以,现在当我开始迭代location变量时,它不会在第一次迭代中中断。它在第二次迭代中中断。当它无法获得与2 中存在的MyClass1对象对应的记录/对象时,它会中断。2没有任何对象。希望这会有所帮助!idmylist1mylist2id

慕仙森

你的e.EquipmentType.Nameisnull并且它被分配给它并且分配给一个类型EquipmentType是非常好的,你正在使用它,如果它不匹配任何条件,它将使用它们的默认值初始化元素,在这种情况下,你被设置为哪个很好我猜。使用它会抛出异常。nullnullableDefaultIfEmpty()e.ElementType.NamenullToList()我希望我说得有道理,你们可能已经讨论过这个问题。
打开App,查看更多内容
随时随地看视频慕课网APP