繁体   English   中英

在c#中访问可空值的最佳方法

[英]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;

如果HasValuefalse则抛出

因此,如果您不想体验InvalidOperationException ,请首先检查HasValue

注意

int yourInt = myInt;

是不合法的(编译时失败)因为int?没有隐式转换int? to int (如果值为null ,那么将int?为没有合理的值)。 你可以说:

int yourInt = (int)myInt;

请注意,如果myIntnull ,则会抛出此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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM