【问题标题】:Compounded Null Checking With Non-Nullable Parameter使用不可为空参数的复合空值检查
【发布时间】:2020-01-15 13:45:39
【问题描述】:

我一直在为即将举行的考试查看一些 MS 参考资料,并发现了一个我不同意答案的所谓以前的问题。

经过考虑,我将发布问题的屏幕截图,而不是浓缩问题,以防万一我抽象出手头问题的任何相关信息。

我的问题是他们给出的答案是 B,而我认为应该是 A,原因如下。

LINQ 查询中的 where 子句有两个条件,它必须与 DateTime 中年份匹配的条件进行比较?对象和方法参数。

但是,我更感兴趣的是为什么他们认为由于参数类型是不可为空的 int 而需要进行空检查。在按值传递参数之前取消赋值和尝试赋值 null 将导致编译器错误。

如果年份参数永远不能为 null,则永远不会有 null DateTime 匹配 - 使 null 检查变得多余。

我知道为什么 B 也会产生预期的结果,但是回答 A 有什么错误

(附言我读过 - Comparing non nullable `int` to `null` (LINQ) 这似乎支持我的理论,我只是对不同意参考资料感到不安)

【问题讨论】:

  • @sam 一个公平的评论 - 我在犹豫是否首先包含图像,但我想将其保持为可读格式,并且不必围绕它创建支持代码。我认为这个问题的创建者的意图是考虑原则,而不是考虑如何将其变为可编译状态。
  • SQL Server 的 DateTime 可以为 null,而 c# DataTime 不可为空。
  • 你应该问查询的作者......回答A如果你考虑到它是EF(因为表达式将被翻译成SQL),AFAIK应该可以工作......但它不会在“plain C#”(其他人写的会抛出异常)
  • fx A 可以直接翻译成 WHERE DATEPART(year, OrderDate) = @year ... 而 B 可以直接翻译成 WHERE OrderDate IS NOT NULL AND DATEPART(year, OrderDate) = @year ... 从 SQL 的角度来看,它们将返回相同的结果

标签: c# linq parameter-passing nullable


【解决方案1】:

假设您选择 A ,如果 Date 为 null 您将得到以下异常

Nullable object must have a value.
  + System.ThrowHelper.ThrowInvalidOperationException(System.ExceptionResource)
  + Nullable<T>.get_Value()

例如

DateTime? dt = null;
 if (dt.Value.Year == 2010) Console.WriteLine("Accepted Value");

给出错误

【讨论】:

  • 但是问题中没有这样的代码...dt.Value.Year直接翻译成SQL代码
【解决方案2】:

申请必须满足以下要求:

  • 仅返回 OrderDate 值不为 null 的订单。
  • 仅返回在 year 参数指定的年份下达的订单

另外,第 1 行似乎向您展示了 OrderDate 的定义

public DateTime? OrderDate;

问题是告诉你OrderDate 是一个可以为空的DateTime 对象,你需要检查它是否有值。

编辑: 我确实使用 SQLEXPRESS 和 LINQPad 5 为自己尝试过这个,现在我看到答案 A 在 LINQ to SQL 的上下文中确实有效,因为它被转换为

WHERE DATEPART(Year,OrderDate) = @year

这将过滤掉 null OrderDates。

那么,我只能说,为什么我认为答案 B 是“首选”答案。

在所有其他 C# 上下文中回答 A 将抛出 InvalidOperationException “Nullable object must have a value”,并且它恰好在此上下文中工作,因为它是 LINQ to SQL。

答案 B 将在 C# 上下文和 LINQ to SQL 上下文中工作,因此在两个可能的答案中,它是最安全的,并且有助于防止您在可能失败的上下文中使用像 A 这样的答案.此外,我相信它更清楚和明确地传达了您想要过滤掉空订单日期。执行额外的 null 检查可能会对性能造成轻微影响,但除非存在可衡量的性能问题,否则可读性比轻微的性能改进更重要。如果我确实使用了答案 A,我将包含大量描述 LINQ to SQL 行为的 cmets,以解释为什么不需要进行 null 检查。

【讨论】:

  • 我很感激 - 但由于 Where 子句的第二部分,如果 DateTime 为空,则永远不会有匹配项。在这种情况下,您需要将 null DateTime 年份值与 永远不会为 null 的值进行比较,但不满足条件,因此 null DateTime 不包含在返回中。
  • 但代码不在 C# 端执行...它直接转换为 SQL fx 到 WHERE DATEPART(y, OrderDate) = @year ...使用此 SQL 代码检查它是否为空是不必要的,因为 int is not equal NULL 在SQL(但也不等于,呵呵所以int !=NULL是假的)
  • @James 如果您不相信答案,那么我唯一的建议就是去尝试一下。我不能说我对 LINQ to SQL 非常有经验,但是在正常的 C# 上下文中,如果您在 OrderDate 为空时调用 order.OrderDate.Value.Year,您将收到运行时异常。
  • @TJRockefeller 我怀疑你和易卜拉欣在告诉我同样的事情。似乎我陷入了将无值(即未分配)和空值等同起来的陷阱。我正在研究 DateTime 的默认未分配值?看看我是否可以确认这一点。
  • @TJRockefeller 我研究了 HasValue ,它几乎是对底层类型的空检查。鉴于可用的答案和 Selvin 的 cmets,未定义 OrderDate 的合法性不太可能在问题范围内。
猜你喜欢
  • 2018-06-05
  • 2023-02-22
  • 1970-01-01
  • 2012-10-29
  • 1970-01-01
  • 1970-01-01
  • 2015-12-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多