9

In our C# code, we already test if a variable is null before attempting to access it.

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

  // do something with yourInt
}

My question: is there a difference in using the nullable property as if it wasn't after it has been tested versus the following?

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

  // do something with yourInt
}

Is this just a matter of preference or is there a distinct reason or performance impact for using .Value even after the nullable object has passed that test?

UPDATE

I expanded on my second example, we already test with HasValue, but there we use .Value to access the value.

UPDATE 2

I updated the examples to use vars because in our code we don't actually use int types, sorry about the poor example. In our code, we actually just use the object inside an NHibernate Criteria query - Expression.Eq("thing", myInt) query.

This doesn't throw a compilation error. I was trying to simplify the example to get to the root of my question without getting NHibernate involved. Sorry if this invalidates some of the answers. I was just trying to see if there is a hit on performance if we force another method to find the value versus explicitly calling .Value.

Community
  • 1
  • 1
shanabus
  • 12,989
  • 6
  • 52
  • 78
  • Using `var` instead of `int` will make no difference in `??? yourInt = myInt.Value;` since C# will infer the type of `yourInt` from the expression to the right which is an `int` expression. `yourInt` will be an `int` in any case. – Olivier Jacot-Descombes Dec 20 '12 at 17:49

4 Answers4

24

UPDATE: This question was the subject of my blog on December 20th, 2012. I'll be following it up with more thoughts on this optimization later in December and early January 2013. Thanks for the great question!


I was just trying to see if there is a hit on performance if we force another method to find the value versus explicitly calling .Value

First off, if you have a performance question then you are the only person who can answer the question, and you answer it by trying it both ways with a stopwatch and seeing which one is faster. It is a mystery to me why people ask this question on StackOverflow so often. It is exactly like saying "Hey internet, here are pictures of two horses. Which one runs faster?" How should we know? Race them, and then you'll know. They're your horses.

Second, you are asking the wrong question in a general sense. The question should not be "is there a hit on performance?", but rather "is there an unacceptable hit on performance?" And again, we do not know what is or is not acceptable to you.

Third, you are asking the wrong question in a very specific sense. The correct question to ask here, if you are interested in nano-scale optimization, is which is faster, using the Value getter or the GetValueOrDefault method?

The answer is that typically the GetValueOrDefault method is faster than Value. Why? Because the difference is the difference between:

if (this.HasValue) return this.value; else throw new Exception();

and

return this.value; 

What's the difference there? The jitter will likely not inline the former method and therefore you are paying a penalty of up to several nanoseconds to make the extra call indirection.

If a penalty of several nanoseconds is relevant to you then (1) congratulations for writing a program that runs in only a few microseconds, and (2) you are going to need to measure extraordinarily carefully to see if there is any real difference, because nanoseconds are pretty darn small.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    sorry to have offended you Eric, you are clearly a better member of the SO community. If you don't like my question you could have not answered it or just flagged it for deletion. Thanks for your time just the same. – shanabus May 02 '12 at 15:52
  • 15
    @shanabus: I'm not *offended* in the least; I am *mystified*! Why do so many people ask "which of these two things is faster?" and expect a reasonable answer other than "try it and then you'll know"? – Eric Lippert May 02 '12 at 16:09
  • 6
    I don't think performance questions are wrong. Testing performance is not an easy task. With two pictures of horses someone might answer "the left one is a cow" preventing you from doing something stupid. "in normal cases it doesn't matter but only testing can tell" is a valid answer to many performance questions. – adrianm May 03 '12 at 06:44
  • 1
    Perhaps if the question were phrased: "Why might one be faster than the other?", would be better. That is effectively the question that Eric has answered here. – MarkPflug May 03 '12 at 14:33
  • 2
    @Mark But then it is a discussion, and this is not a discussion forum. – asawyer May 03 '12 at 17:53
  • 1
    This answer is a great explanation, but comes across (to me, and apparently to the OP) as excessively harsh. You could probably open with the section with the actual answer ("*The answer is that typically the GetValueOrDefault method is faster...*"), and move all the chiding and ranting to the end of the post. – Josh Darnell May 11 '12 at 16:23
  • 1
    No, the difference between the getter code of the `Value` property and the `GetValueOrDefault()` method is greater than you indicate here! If you look at the source code, you will se that `GetValueOrDefault()` simply says: `return value;`. No `if` check is needed because, from the way a `Nullable<>` is constructed, we can guarantee that the internal `value` field is always `default(T)` if `hasValue` is false. So `GetValueOrDefault()` is faster because it needs no check; it actually "unwraps" the `value` without looking at the `hasValue` boolean! – Jeppe Stig Nielsen Jul 08 '12 at 09:34
15

is this just a matter of preference or is there a distinct reason

int yourInt = myInt.Value;

will throw if HasValue is false.

Thus, if you don't want to experience InvalidOperationExceptions, check HasValue first.

Note that

int yourInt = myInt;

is not legal (compile-time failure) because there is no implicit conversion from int? to int (what if the value is null; there's no reasonable value to cast the int? to). You can say:

int yourInt = (int)myInt;

Note that this will throw if myInt is null though, just like accessing Value.

One last note, if you're okay with accepting a default value, you can use the null coalescing operator and say:

int yourInt = myInt ?? defaultValue;

This is equivalent to:

int yourInt;
if(myInt.HasValue) {
    yourInt = myInt.Value;
}
else {
    yourInt = defaultValue;
}

This doesn't throw a compilation error. I was trying to simplify the example to get to the root of my question without getting NHibernate involved. Sorry if this invalidates some of the answers. I was just trying to see if there is a hit on performance if we force another method to find the value versus explicitly calling .Value.

No. Performance is totally irrelevant here, especially if there is a database involved. This is absolutely not going have any meaningful performance difference, and will certainly not be a bottleneck. Just write the clearest code. Frankly, I find .Value to be the clearest.

jason
  • 236,483
  • 35
  • 423
  • 525
  • 1
    You can also write `if(myInt != null) { ... }`. I find this more clear than using `HasValue` property. – Marek Dzikiewicz May 02 '12 at 14:36
  • Thanks for your response. I updated my question as I meant for the second example to show that we still do the test, we just don't access it through the `.Value` method. Maybe my example is still poor because we're not just setting it to an `int`, we're throwing it into a function that accepts `object`. – shanabus May 02 '12 at 14:43
  • @shanabus: Please see my edit. Performance is not a concern here. – jason May 02 '12 at 14:59
2

This code is invalid:

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

  // do something with yourInt
}

If you didn't want to use the Value property, you'd have to use an explicit cast instead, or the null coalescing operator, or GetValueOrDefault, e.g.

int yourInt = (int) myInt;

The cast ends up being compiled as access to the Value property anyway, IIRC.

So yes, even after you've tested that a value is non-null, you still have to do something to convert it to the underlying value - just to get it to compile. The compiler doesn't try to analyze the "possible nullity" (imagine if it's an instance variable, for example, which could change due to threading between accesses). It just follows the rules for what you're allowed to do with a nullable expression, and implicit conversion to the non-nullable type isn't one of those things you're allowed to do...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
-2

There is a reason why you can't call .Value direct: what would you expect the value of yourInt to be when the myInt is null?

When you want to have it a default value (for instance: 0), you can create an extensionmethod on the nullable int like .ValueOrDefault().

Michel
  • 23,085
  • 46
  • 152
  • 242