繁体   English   中英

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

[英]Why am I NOT getting a Null Reference Exception?

我正在使用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。 我的EquipmentClass有一个属性类型EquipmentType ,它是另一个类。 EquipmentType具有Name属性,该属性是String。

  1. 为什么不抛出空引用异常?

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

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

更新

foreach (var item in location)
{
    var p = item.EquipmentClass.EquipmentType.Name;
}

在查询后添加此权限。 在p的赋值上,我得到一个空引用异常。 我不确定它到底是怎么回事,因为它应该在foreach循环的第一行失败。 如果没有声明变量p的行, 我就不会得到空引用异常 如果有人能解释发生了什么,我将不胜感激。 仅供参考,在foreach循环开始时, item.EquipmentClassitem.EquipmentType的值都为null。

Update2:我发现这个链接似乎有人使用LINQ to SQL几乎完全相同。 我得到了答案的要点,但没有完全理解它对我上面两个问题的潜在影响。

如果您针对IQueryable编写LINQ查询,那么您在幕后调用的方法(例如SelectWhere等)除了记录您调用它们的方式之外不会做任何事情,即它们记录谓词表达式并继承LINQ提供程序。 一旦开始迭代查询, 就会要求提供程序执行查询模型 基本上,提供程序使用表达式模型为您提供预期类型的​​结果。

提供者绝不需要实际编译甚至执行您作为表达式提供的代码(模型)。 事实上,LINQ to SQL或LINQ to Entities的重点是提供程序不执行此操作并将代码表达式转换为SQL。

因此,您的查询实际上呈现为SQL查询,并且该查询的结果将被转换回来。 因此,您在查询中看到的变量e不一定是真正创建的,而只是用于LINQ提供程序来编译SQL查询。 但是,大多数数据库服务器都具有空传播。

对LINQ to Objects运行相同的查询,您将获得缺少的NullReferenceException

您的更新帮助我了解您真正关心的问题。 关于LINQ查询,您需要了解的概念是LINQ中的延迟执行

请通过以下链接了解更多详情:

LINQ中的延迟执行有什么好处?

Linq - 找出延期执行的最快方法是什么?

现在你的情况会发生什么? 您已将查询存储在location变量中。 该特定步骤仅仅是初始化部分。 它并不真正通过ORM层在您的数据库上执行查询。 这是你如何测试这个。

在使用LINQ查询初始化location变量的代码行上放置一个断点。 当调试器在Visual Studio中停止时,请转到SQL Server Management Studio(SSMS)并启动SQL Server Profiler会话。

现在按Visual Studio中的F10来跳过代码语句。 此时您将在Profiler会话中看到绝对没有查询执行,如下所示:

在此输入图像描述

这都是因为直到这个时间点LINQ查询都没有执行。

现在,您可以访问以下代码行:

foreach (var item in location)
{
    var p = item.EquipmentClass.EquipmentType.Name;
}

当您进入foreach循环时,LINQ查询将被触发,您将在SQL Server探查器中看到相应的跟踪会话日志。 因此,除非枚举它,否则不会触发LINQ查询。 这称为延迟执行,即运行时将执行推迟到枚举。 如果您从未在代码中枚举location变量,那么查询执行将永远不会发生。

因此,要回答您的查询,只有在查询被触发时才会出现异常。 不是在那之前!

更新1 :你说的是 - 我没有得到空引用异常 是! 在到达缺少相应RHS连接记录的记录之前,您将不会获得空引用异常。 请查看以下代码以便更好地理解:

class Program
{
    static void Main(string[] args)
    {
        var mylist1 = new List<MyClass1>();
        mylist1.Add(new MyClass1 { id = 1, Name1 = "1" });
        mylist1.Add(new MyClass1 { id = 2, Name1 = "2" });

        var mylist2 = new List<MyClass2>();
        mylist2.Add(new MyClass2 { id = 1, Name2 = "1" });

        var location = from l in mylist1
                       join e in mylist2 on l.id equals e.id into rs1
                       from e in rs1.DefaultIfEmpty()
                       //where ids.Contains(l.ID)
                       select new
                       {
                           EquipmentClass = e,
                           InServiceStatus = e == null ? 1 : e.id,
                           EquipmentType = e.id
                       };

        foreach (var item in location)
        {

        }
    }
}

class MyClass1
{
    public int id { get; set; }
    public string Name1 { get; set; }
}

class MyClass2
{
    public int id { get; set; }

    public string Name2 { get; set; }
}

所以,现在当我开始迭代location变量时,它在第一次迭代中不会中断。 它在第二次迭代中断。 当它不能获得对应于该记录/对象它打破MyClass1对象具有id 2存在于mylist1 mylist2没有id 2的任何对象。希望这有帮助!

你的e.EquipmentType.Namenull并且它被分配给EquipmentType并且将null分配给nullable类型并且你正在使用DefaultIfEmpty() ,如果它无法匹配任何条件,它将使用它们的默认值初始化它们。在这种情况下,你的e.ElementType.Name被设置为null ,我想这很好。 使用ToList()将抛出异常。

我希望我有一些意义,你们可能会讨论这个问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM