public class BenchmarkNullableCheck
{
static int? x = (new Random()).Next();
public static bool CheckObjectImpl(object o)
{
return o != null;
}
public static bool CheckNullableImpl<T>(T? o) where T: struct
{
return o.HasValue;
}
[Benchmark]
public bool CheckObject()
{
return CheckObjectImpl(x);
}
[Benchmark]
public bool CheckNullable()
{
return CheckNullableImpl(x);
}
}
6 回答
编译器将空比较替换为对
HasValue
的调用,因此没有真正的区别 . 只要做一个对您和您的同事更具可读性/更有意义的事情 .我更喜欢
(a != null)
,以便语法与引用类型匹配 .我通过使用不同的方法将值赋给可空int来对此进行了一些研究 . 这是我做各种事情时发生的事情 . 应该澄清发生了什么 . 请记住:
Nullable<something>
或简写something?
是一个结构,编译器似乎正在做很多工作,让我们使用null,就像它是一个类一样 .正如您将在下面看到的那样,
SomeNullable == null
和SomeNullable.HasValue
将始终返回预期的true或false . 虽然下面没有说明,SomeNullable == 3
也是有效的(假设SomeNullable是int?
) .如果我们将
null
分配给SomeNullable
,SomeNullable.Value
会给我们带来运行时错误 . 事实上,这是唯一一个由于重载运算符,重载object.Equals(obj)
方法以及编译器优化和猴子业务的组合,nullables可能导致我们出现问题的情况 .以下是我运行的一些代码的说明,以及它在标签中生成的输出:
好的,让我们尝试下一个初始化方法:
和以前一样 . 请记住,使用
int? val = new int?(null);
初始化,并将null传递给构造函数,会产生COMPILE时间错误,因为可空对象的VALUE不可为空 . 只有包装器对象本身才能等于null .同样,我们会得到一个编译时错误:
更不用说
val.Value
无论如何都是一个只读属性,这意味着我们甚至不能使用类似的东西:但同样,多态重载隐式转换运算符让我们做:
不管怎么说,只要它能正常工作,就不用担心多元化的问题了吗? :)
在VB.Net中 . 当你可以使用“.HasValue”时,不要使用“IsNot Nothing” . 我刚刚在一个地方用“.HasValue”替换了“IsNot Nothing”,解决了“操作可能使运行时不稳定”的中等信任错误 . 我真的不明白为什么,但在编译器中发生了不同的事情 . 我认为C#中的“!= null”可能会有同样的问题 .
如果您使用linq并希望保持代码简短,我建议始终使用
!=null
这就是为什么:
假设我们有一个
Foo
类 nullable double 变量SomeDouble
如果在我们的代码中的某个地方,我们希望从Foo的集合中获取所有Foo的非空SomeDouble值(假设集合中的某些foos也可以为null),我们最终至少有三种方式来编写我们的函数(如果我们使用C#6):
在这种情况下,我建议总是选择较短的一个
一般答案和经验法则:如果您有一个选项(例如编写自定义序列化程序)来处理不同于
object
的管道中的Nullable - 并使用它们的特定属性 - 请执行此操作并使用Nullable特定属性 . 所以从一致的思维角度来看HasValue
应该是首选 . 一致的思考可以帮助你编写更好的代码,不要在细节上花太多时间 . 例如 . 第二种方法将会多次有效(主要是因为编译器内联和装箱,但仍然数字很有表现力):基准测试:
基准代码:
使用了https://github.com/dotnet/BenchmarkDotNet
PS . 人们说建议"prefer HasValue because of consistent thinking"没有关联和无用 . Can you predict the performance of this?
PPS 人们继续减去,但没有人试图预测
CheckNullableGenericImpl
的表现 . 并且编译器不会帮助您用HasValue
替换!=null
. 如果您对性能感兴趣,应直接使用HasValue
.