[英]Best way to access nullable values in c#
在我们的C#代码中,我们已经在尝试访问变量之前测试了变量是否为null。
if (myInt.HasValue) {
var yourInt = myInt;
// do something with yourInt
}
我的问题:使用可空属性是否有区别,就好像它在测试之后不是以下情况一样?
if (myInt.HasValue) {
var yourInt = myInt.Value; // see the difference?
// do something with yourInt
}
这只是一个偏好问题,或者即使在可以为空的对象通过该测试之后,使用.Value
还是有明显的原因或性能影响吗?
UPDATE
我扩展了我的第二个例子,我们已经使用HasValue
测试,但我们使用.Value
来访问该值。
更新2
我更新了示例以使用var
s,因为在我们的代码中我们实际上并没有使用int
类型,抱歉这个糟糕的例子。 在我们的代码中,我们实际上只是使用NHibernate Criteria查询中的对象 - Expression.Eq("thing", myInt)
查询。
这不会引发编译错误。 我试图简化示例以获得我的问题的根源而不涉及NHibernate。 很抱歉,如果这会使某些答案无效。 如果我们强制使用另一种方法来查找值而不是显式调用.Value
我只是想看看性能是否受到打击。
更新:这个问题是我2012年12月20日的博客主题 。 我将在2013年12月和1月初的更多关于此优化的想法中跟进。感谢您提出的好问题!
如果我们强制使用另一种方法来查找值而不是显式调用.Value,我只是想看看性能是否受到打击
首先,如果您有性能问题,那么您是唯一可以回答问题的人 ,并且您可以通过秒表尝试两种方式并查看哪一个更快 来回答问题 。 对我来说,为什么人们经常在StackOverflow上问这个问题,这是一个谜。 这就像说“嘿,互联网,这里有两匹马的照片。哪一个跑得更快?” 我们怎么知道? 比赛他们,然后你会知道。 他们是你的马。
其次,你在一般意义上提出错误的问题。 问题不应该是“是否会对性能产生影响?”而是“对性能造成不可接受的打击?” 而且,我们不知道您接受或不接受的是什么。
第三,你是在非常具体的意义上提出错误的问题。 这里要问的正确问题是,如果您对纳米级优化感兴趣,使用Value getter或GetValueOrDefault方法哪个更快?
答案是通常GetValueOrDefault方法比Value快。 为什么? 因为区别在于:
if (this.HasValue) return this.value; else throw new Exception();
和
return this.value;
那有什么区别? 抖动可能不会内联前一种方法 ,因此您需要支付高达几纳秒的罚款才能实现额外的呼叫间接。
如果几纳秒的罚款与你相关,那么(1)祝贺编写一个只运行几微秒的程序,(2)你需要非常仔细地测量,看看是否有任何真正的差异,因为纳秒非常小。
这只是一个偏好问题还是有一个明显的原因
int yourInt = myInt.Value;
如果HasValue
为false
则抛出
因此,如果您不想体验InvalidOperationException
,请首先检查HasValue
。
注意
int yourInt = myInt;
是不合法的(编译时失败)因为int?
没有隐式转换int?
to int
(如果值为null
,那么将int?
为没有合理的值)。 你可以说:
int yourInt = (int)myInt;
请注意,如果myInt
为null
,则会抛出此null
,就像访问Value
。
最后一点,如果您接受默认值,则可以使用null合并运算符并说:
int yourInt = myInt ?? defaultValue;
这相当于:
int yourInt;
if(myInt.HasValue) {
yourInt = myInt.Value;
}
else {
yourInt = defaultValue;
}
这不会引发编译错误。 我试图简化示例以获得我的问题的根源而不涉及NHibernate。 很抱歉,如果这会使某些答案无效。 如果我们强制使用另一种方法来查找值而不是显式调用.Value,我只是想看看性能是否受到打击。
没有。性能在这里完全无关紧要,特别是如果涉及数据库的话。 这绝对没有任何有意义的性能差异,并且肯定不会成为瓶颈。 只需编写最清晰的代码即可。 坦率地说,我发现.Value
是最清楚的。
此代码无效:
if (myInt.HasValue) {
int yourInt = myInt;
// do something with yourInt
}
如果您不想使用Value
属性,则必须使用显式强制转换,或使用null合并运算符或GetValueOrDefault
,例如
int yourInt = (int) myInt;
无论如何,演员最终被编译为对Value
属性的访问,IIRC。
所以,是的,即使你已经测试过一个值是非空的,你仍然需要做一些事情来将它转换为底层值 - 只是为了让它进行编译。 编译器不会尝试分析“可能的无效”(例如,如果它是一个实例变量,例如,由于访问之间的线程可能会改变)。 它只遵循允许对可以为空的表达式执行的操作的规则,并且隐式转换为非可空类型不是您允许执行的操作之一...
有一个原因你不能直接调用.Value
:当myInt
为null时,你会期望yourInt
的值是多少?
如果要使其具有默认值(例如:0),则可以在可空的int上创建扩展方法,如.ValueOrDefault()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.