首选:Nullable <>.HasValue或Nullable <>!= null?

lc.*_*lc. 408 .net c# null nullable

我总是使用(a)Nullable<>.HasValue因为我喜欢语义.然而,最近我正在研究其他人现有的代码库,他们Nullable<> != null专门使用(b)代替.是否有理由使用一个而不是另一个,还是纯粹的偏好?

(一个)

int? a;
if (a.HasValue)
    // ...
Run Code Online (Sandbox Code Playgroud)

(b)中

int? b;
if (b != null)
    // ...
Run Code Online (Sandbox Code Playgroud)

Rex*_*x M 440

编译器将null比较替换为调用HasValue,因此没有真正的区别.只要做一个对您和您的同事更具可读性/更有意义的事情.

  • 我会补充说"无论哪个更符合/遵循现有的编码风格." (81认同)
  • 在创建应用程序的早期阶段,您可能认为使用可空值类型来存储某些数据是足够的,只是在一段时间后才意识到您需要一个适合您目的的类.编写原始代码以与null进行比较后,您的优势在于您不需要使用null比较来搜索/替换对HasValue()的每次调用. (22认同)
  • 哇.我讨厌这种语法糖.`诠释?x = null`让我觉得可以为空的实例是一个引用类型.但事实是Nullable <T>是一种值类型.我觉得我会得到一个NullReferenceException:`int?x = null; 使用(x.HasValue)`. (18认同)
  • 抱怨能够将Nullable设置为null或将其与null进行比较是非常愚蠢的,因为它被称为Nullable**.问题是人们将"引用类型"与"可以为空"混为一谈,但这是一个概念上的混淆.Future C#将具有不可为空的引用类型. (12认同)
  • @KFL如果语法糖困扰你,只需使用`Nullable <int>`而不是`int?`. (11认同)
  • @KFL我有时会使用`var z = x ?? y`为可空类型.你还喜欢`var z = x.HasValue吗?x:y`在那种情况下?看起来有点怪异. (2认同)

cbp*_*cbp 43

我更喜欢(a != null)语法匹配引用类型.

  • 它只会误导概念上的困惑.对两种不同类型使用一致的语法并不意味着它们是相同的类型.C#具有可为空的引用类型(所有引用类型当前都可以为空,但将来会发生变化)和可空值类型.对所有可空类型使用一致的语法是有意义的.它绝不意味着可空值类型是引用类型,或者可空引用类型是值类型. (30认同)
  • 当然,这是非常误导的,因为`Nullable <>`不是*参考类型. (9认同)
  • 是的,但事实上通常很重要,因为你是空检查. (7认同)
  • 绝对投票支持这种偏好,如果没有别的办法的话,它会让编码更改更简单,因为从引用类型到可为空类型不需要在其他任何地方更改代码,而一旦不再显式使用“.HasValue”,它就会变成不正确的语法“Nullable”,这可能不是常见情况,但如果您曾经为了 Tuple 编写过一个结构体,然后将其转换为一个类,那么您就已经处于适用的领域,并且随着 NullableRefs 的出现,这个将变得更有可能发生。 (2认同)

Per*_*son 21

我通过使用不同的方法将值赋给可空int来对此进行了一些研究.这是我做各种事情时发生的事情.应该澄清发生了什么.请记住:Nullable<something>或者简写something?是一个结构,编译器似乎正在做很多工作,让我们使用null,就像它是一个类一样.
正如您将在下面看到的那样,SomeNullable == null并且SomeNullable.HasValue将始终返回预期的真或假.虽然下面没有说明,但SomeNullable == 3也是有效的(假设SomeNullable是一个int?).
虽然SomeNullable.Value得到了我们一个运行时错误,如果我们分配nullSomeNullable.事实上,这是唯一一个由于重载运算符,重载object.Equals(obj)方法,编译器优化和猴子业务的组合,nullables可能导致我们出现问题的情况.

以下是我运行的一些代码的说明,以及它在标签中生成的输出:

int? val = null;
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
Run Code Online (Sandbox Code Playgroud)

好的,让我们尝试下一个初始化方法:

int? val = new int?();
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
Run Code Online (Sandbox Code Playgroud)

和以前一样.请记住int? val = new int?(null);,使用null传递给构造函数初始化会产生COMPILE时间错误,因为可空对象的VALUE不可为空.只有包装器对象本身才能等于null.

同样,我们会得到一个编译时错误:

int? val = new int?();
val.Value = null;
Run Code Online (Sandbox Code Playgroud)

更何况这val.Value是一个只读属性,这意味着我们甚至不能使用类似的东西:

val.Value = 3;
Run Code Online (Sandbox Code Playgroud)

但同样,多态重载隐式转换运算符让我们做:

val = 3;
Run Code Online (Sandbox Code Playgroud)

不管怎么说,只要它能正常工作,就不用担心多元化的问题了吗?:)

  • "请记住:Nullable <something>或简写的东西?是一个类." 这是错的!Nullable <T>是一个结构.与null相比,它重载Equals和==运算符以返回true.编译器没有花哨的工作来进行这种比较. (5认同)
  • @andrewjs实际上,编译器在优化nullables方面做了大量工作.例如,如果为可归类型赋值,则它实际上根本不可为空(例如,`int?val = 42; val.GetType()== typeof(int)`).因此,不仅可以为一个可以等于null的结构,而且它通常也不是可以为空的!:D同样的方式,当你装入一个可以为空的值时,你是装箱`int`,而不是`int?` - 当`int?`没有值时,你得到`null`而不是盒装可空的价值.它基本上意味着很少有正确使用可空的任何开销:) (3认同)

Car*_*lin 13

在VB.Net中.当你可以使用".HasValue"时,不要使用"IsNot Nothing".我刚刚在一个地方用".HasValue"替换了"IsNot Nothing",解决了"操作可能使运行时不稳定"的中等信任错误.我真的不明白为什么,但在编译器中发生了不同的事情.我认为C#中的"!= null"可能会有同样的问题.

  • @steffan"IsNot Nothing"不是双重否定."没有"不是负面的,它是一个离散的数量,即使在编程领域之外."这个数量不算什么." 在语法上,与说"这个数量不是零"完全相同.并且都不是双重否定. (12认同)
  • 因为可读性,我更喜欢'HasValue`."IsNot Nothing"真的是一个丑陋的表达(因为双重否定). (8认同)
  • 这并不是说我不想在这里不同意真相,而是现在来吧.IsNot没有什么是明显的,过分消极的.为什么不写一些像HasValue一样积极和清晰的东西?这不是语法测试,而是编码,关键目标是清晰度. (4认同)
  • jmbpiano:我同意这不是双重否定,但它是一个单一的否定,这几乎就像一个简单的积极表达一样丑陋而不清晰. (3认同)