Razor 页面中访问本地非 null 变量的 NullReferenceException

NullReferenceException in razor page accessing local, non-null variable

提问人:Mahmoud Al-Qudsi 提问时间:3/21/2023 更新时间:3/21/2023 访问量:64

问:

我在 cshtml Razor 页面中遇到了一个非常奇怪的情况,其中块中的常规代码可以很好地访问和使用变量,但是尝试访问相同的变量但在上下文中会抛出 s。@{ ... }@(...)NullReferenceException

为了调试这个问题,我移动了模型属性导航和对绝对非 null 的局部变量的访问,然后尝试使用块打印它,但仍然存在。@(..)NullReferenceException

@foreach (var sibling in Model.SiblingApplications)
{
    string studentName = sibling.Student.ToString() ?? "";

    <div class="sibling half line">
        <div class="question-block grow">
            <div class="label">Name</div>
            @* NullReferenceException on the next line! *@
            <div class="value">@studentName</div>
        </div>
    </div>
}

最初,它来自直接编写,即使我在它上面添加了断言以抛出属性访问或覆盖 where 使用的任何变量。然后,我将代码重构为您在上面看到的内容,将变量存储在非 null 字符串中(并通过附加偏执狂来加倍确保这种情况)。NullReferenceException@(sibling.Student)ToString()null?? ""

尽管如此,仍然存在。我无法在调试或发布模式下本地观察到该问题,但它不会失败并记录在生产中。我尝试从 .NET 7 降级到 .NET 6,并尝试部署 Debug 版本而不是 Release,但这些都没有帮助。NullReferenceException

堆栈跟踪没有帮助;它只是指向上面注释的行:NullReferenceException

System.NullReferenceException: Object reference not set to an instance of an object.
   at ProjectName.Pages.Forms.Pages_Forms_RegistrationForm.ExecuteAsync() in X:\ProjectPath\Pages\Forms\RegistrationForm.cshtml:line 240
...

重要的是,在实际访问模型属性并生成非 null 字符串的代码上不会引发异常 - 同样,异常发生在访问这个 now-local、绝对不是 null 的变量时。

C# Razor Razor-Pages NullReferenceException

评论

0赞 Brad 3/21/2023
该错误似乎无法访问它,但它没有填充/启动,因此它是 NULL。
0赞 derpirscher 3/21/2023
如果为 null,您的代码仍将抛出sibling.Student
0赞 HasaniH 3/21/2023
你是说吗?如果为 null,则将抛出,而不是为运算符提供 null。string studentName = sibling.Student?.ToString() ?? "";sibling.Student.ToString()??
0赞 Mahmoud Al-Qudsi 3/21/2023
@HasaniH不,我不是那个意思。代码不会抛出(在那一行上),所以显然是非空的。如果重写出于某种原因返回 null 字符串,则为 is。sibling.Student?? ""ToString()
0赞 Mahmoud Al-Qudsi 3/21/2023
@derpirscher是的,但是堆栈跟踪会告诉我异常发生在哪一行,我会知道这是因为 null - 但这不会发生。(我实际上添加了一个守卫来检查该值是否为 null 并抛出异常,并且我记录了 to seq 的值,并且该值不为 null)。sibling.Studentsibling.Student

答:

0赞 Mahmoud Al-Qudsi 3/21/2023 #1

如果不附加调试器,我无法弄清楚这一点,之后它立即变得清晰起来。(弄清楚如何在生产中附加调试器是另一回事。

虽然异常确实是在带注释的行上引发的,但在调试器中,会显示导致异常的变量,尽管它在记录的实际异常消息或堆栈跟踪中命名。NullReferenceException

事实证明,(由于优化?)编译器一次性取消了两个不同的值,(在同一行上使用)和(在同一个for循环中使用了几行,上面发布的缩写示例中没有显示)。@sibling.Student@sibling.AnotherProperty

第二次访问实际上导致了 ,尽管堆栈跟踪和调试器(甚至在调试模式下附加)都在第一行的末尾抛出/中断。NullReferenceException

我以前想知道是否有可能让记录的异常和堆栈跟踪实际上包含调试器发出的相同信息(即,发生时被取消引用的属性或变量,而不仅仅是行号) - 这将为我(和你)省去很多悲伤。NullReferenceException