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

sha*_*bus 5 c# nhibernate nullable hibernate-criteria

在我们的C#代码中,我们已经在尝试访问变量之前测试了变量是否为null.

if (myInt.HasValue) {
  var yourInt = myInt;

  // do something with yourInt
}
Run Code Online (Sandbox Code Playgroud)

我的问题:使用可空属性是否有区别,就好像它在测试之后不是以下情况一样?

if (myInt.HasValue) {
  var yourInt = myInt.Value; // see the difference?

  // do something with yourInt
}
Run Code Online (Sandbox Code Playgroud)

这只是一个偏好问题,或者.Value即使在可以为空的对象通过该测试之后,是否存在明显的原因或性能影响?

UPDATE

我扩展了我的第二个例子,我们已经测试过HasValue,但我们用它.Value来访问该值.

更新2

我更新了示例以使用vars,因为在我们的代码中我们实际上并没有使用int类型,抱歉这个糟糕的例子.在我们的代码中,我们实际上只是使用NHibernate Criteria查询中的对象 - Expression.Eq("thing", myInt)查询.

这不会引发编译错误.我试图简化示例以获得我的问题的根源而不涉及NHibernate.很抱歉,如果这会使某些答案无效.如果我们强制使用另一种方法来查找值而不是显式调用,我只是试图查看性能是否受到打击.Value.

Eri*_*ert 24

更新:这个问题是我2012年12月20日的博客主题.我将在2013年12月和1月初的更多关于此优化的想法中跟进.感谢您提出的好问题!


如果我们强制使用另一种方法来查找值而不是显式调用.Value,我只是想看看性能是否受到打击

首先,如果您有性能问题,那么您是唯一可以回答问题的人,并且您可以通过秒表尝试两种方式并查看哪一个更快来回答问题.对我来说,为什么人们经常在StackOverflow上问这个问题,这是一个谜.这就像说"嘿,互联网,这里有两匹马的照片.哪一个跑得更快?" 我们怎么知道? 比赛他们,然后你会知道.他们是你的马.

其次,你在一般意义上提出错误的问题.问题不应该是"是否会对性能产生影响?"而是" 对性能造成不可接受的打击?" 而且,我们不知道您接受或不接受的是什么.

第三,你是在非常特殊的意义上提出错误的问题.这里要问的正确问题是,如果您对纳米级优化感兴趣,使用Value getter或GetValueOrDefault方法哪个更快?

答案是通常GetValueOrDefault方法比Value快.为什么?因为区别在于:

if (this.HasValue) return this.value; else throw new Exception();
Run Code Online (Sandbox Code Playgroud)

return this.value; 
Run Code Online (Sandbox Code Playgroud)

那有什么区别? 抖动可能不会内联前一种方法,因此您需要支付高达几纳秒的罚款才能实现额外的呼叫间接.

如果几纳秒的罚款与你相关,那么(1)祝贺编写一个只运行几微秒的程序,(2)你需要非常仔细地测量,看看是否有任何真正的差异,因为纳秒非常小.

  • @shanabus:我至少没有冒犯过*; 我是*神秘的*!为什么这么多人会问"这两件事中哪一件更快?" 并期待一个合理的答案,除了"尝试它,然后你会知道"? (15认同)
  • 我不认为表演问题是错误的.测试性能不是一件容易的事.有两张马的照片,有人可能会回答"左边的一头是牛"会阻止你做一些愚蠢的事情."在正常情况下,无关紧要,但只有测试可以说明"是许多性能问题的有效答案. (5认同)
  • @Mark然后这是一个讨论,这不是一个讨论论坛. (2认同)

jas*_*son 13

这只是一个偏好问题还是有一个明显的原因

int yourInt = myInt.Value;
Run Code Online (Sandbox Code Playgroud)

如果HasValue是,将扔false.

因此,如果您不想体验InvalidOperationExceptions,请先检查HasValue.

注意

int yourInt = myInt;
Run Code Online (Sandbox Code Playgroud)

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

int yourInt = (int)myInt;
Run Code Online (Sandbox Code Playgroud)

请注意,这将抛出,如果myIntnull,就像访问Value.

最后一点,如果您接受默认值,则可以使用null合并运算符并说:

int yourInt = myInt ?? defaultValue;
Run Code Online (Sandbox Code Playgroud)

这相当于:

int yourInt;
if(myInt.HasValue) {
    yourInt = myInt.Value;
}
else {
    yourInt = defaultValue;
}
Run Code Online (Sandbox Code Playgroud)

这不会引发编译错误.我试图简化示例以获得我的问题的根源而不涉及NHibernate.很抱歉,如果这会使某些答案无效.如果我们强制使用另一种方法来查找值而不是显式调用.Value,我只是想看看性能是否受到打击.

没有.性能在这里完全无关紧要,特别是如果涉及数据库的话.这绝对没有任何有意义的性能差异,并且肯定不会成为瓶颈.只需编写最清晰的代码即可.坦率地说,我发现.Value是最清楚的.