我总是使用Nullable<>。HasValue,因为我喜欢这个语义。然而,最近我正在研究别人的现有代码库,他们专门使用Nullable<> != null。
有理由使用其中一种而不是另一种吗,还是纯粹的偏好?
int ?一个; 如果(a.HasValue) / /……
vs.
int ?b; If (b != null) / /……
我总是使用Nullable<>。HasValue,因为我喜欢这个语义。然而,最近我正在研究别人的现有代码库,他们专门使用Nullable<> != null。
有理由使用其中一种而不是另一种吗,还是纯粹的偏好?
int ?一个; 如果(a.HasValue) / /……
vs.
int ?b; If (b != null) / /……
当前回答
在VB。Net,当你可以使用. hasvalue时,不要使用IsNot Nothing。我刚刚解决了一个“操作可能会破坏运行时”的中等信任错误,将IsNot Nothing替换为. hasvalue。我不太明白为什么,但是在编译器中发生了一些不同的事情。我认为c#中的!= null可能有同样的问题。
其他回答
I did some research on this by using different methods to assign values to a nullable int. Here is what happened when I did various things. Should clarify what's going on. Keep in mind: Nullable<something> or the shorthand something? is a struct for which the compiler seems to be doing a lot of work to let us use with null as if it were a class. As you'll see below, SomeNullable == null and SomeNullable.HasValue will always return an expected true or false. Although not demonstrated below, SomeNullable == 3 is valid too (assuming SomeNullable is an int?). While SomeNullable.Value gets us a runtime error if we assigned null to SomeNullable. This is in fact the only case where nullables could cause us a problem, thanks to a combination of overloaded operators, overloaded object.Equals(obj) method, and compiler optimization and monkey business.
下面是我运行的一些代码的描述,以及它在标签中产生的输出:
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.")
好的,让我们尝试下一个初始化方法:
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.")
和以前一样。记住,初始化int?val = new int?(null);,将null传递给构造函数,将产生COMPILE时错误,因为可空对象的VALUE是不可空的。只有包装器对象本身可以等于null。
同样地,我们会从下面得到一个编译时错误:
int? val = new int?();
val.Value = null;
更不用说val.Value是一个只读属性,这意味着我们甚至不能使用这样的属性:
val.Value = 3;
但同样,多态重载隐式转换操作符让我们做到:
val = 3;
没有必要担心多物什么的,只要它工作对吗?:)
编译器将null比较替换为对HasValue的调用,因此没有真正的区别。选择对你和你的同事来说更有可读性/更有意义的就行。
如果你使用linq并且想要保持你的代码简短,我建议总是使用!=null
原因如下:
假设我们有一个类Foo,它有一个可空的双变量SomeDouble
public class Foo
{
public double? SomeDouble;
//some other properties
}
如果在代码中的某个地方,我们想从Foo集合中获取所有具有非空SomeDouble值的Foo(假设集合中的一些Foo也可以为空),我们最终至少有三种方法来编写我们的函数(如果我们使用c# 6):
public IEnumerable<Foo> GetNonNullFoosWithSomeDoubleValues(IEnumerable<Foo> foos)
{
return foos.Where(foo => foo?.SomeDouble != null);
return foos.Where(foo=>foo?.SomeDouble.HasValue); // compile time error
return foos.Where(foo=>foo?.SomeDouble.HasValue == true);
return foos.Where(foo=>foo != null && foo.SomeDouble.HasValue); //if we don't use C#6
}
在这种情况下,我建议总是选择较短的那条
我更喜欢(a != null),以便语法匹配引用类型。
在VB。Net,当你可以使用. hasvalue时,不要使用IsNot Nothing。我刚刚解决了一个“操作可能会破坏运行时”的中等信任错误,将IsNot Nothing替换为. hasvalue。我不太明白为什么,但是在编译器中发生了一些不同的事情。我认为c#中的!= null可能有同样的问题。