简体   繁体   中英

Best way to access nullable values in c#

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 var s 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 .

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.

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 InvalidOperationException s, 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.

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 , eg

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...

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() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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