After reading the article on DasCode.Net about the ?? operator, I gave my opinion and made the point that you should rather use GetValueOrDefault(). With that said I started playing around with a simple application, 2 variances using each one of these syntaxes.
To use ?? or GetValueOrDefault you have to declare a Nullable type variable e.g int? x = null;
?? is known as the null-coalescing operator and is used to define a default value for nullable value types as well as reference types. It returns the left-hand operand if it is not null; otherwise it returns the right operand. As explained on MSDN.
Application 1:
1: //you have to declare a nullable type
2: int? x = null;
3:
4: int y = x ?? 0;
5:
6: //you have to add brackets around x ?? 0,
7: //because it is converted to a conditional operator
8: if ((x ?? 0) == 0)
9: {
10: Console.WriteLine("x is zero(0).");
11: }
Reflector 1:
1: private static void Main(string[] args)
2: {
3: int? x = null;
4: int? CS$0$0000 = x;
5: int y = CS$0$0000.HasValue ? CS$0$0000.GetValueOrDefault() : 0;
6: CS$0$0000 = x;
7: if ((CS$0$0000.HasValue ? CS$0$0000.GetValueOrDefault() : 0) == 0)
8: {
9: Console.WriteLine("x is zero(0).");
10: }
11: }
Line 4 of Application 1 - is using int y = x ?? 0;. In reflector this code is changed to a conditional operator using the HasValue (property) and GetValueOrDefault() (method) from the Nullable class.
Line 8 of Application 1 - is using if ((x ?? 0) == 0) which in turn is also changed to a conditional operator, showing why you need to add the brackets around x ?? 0.
GetValueOrDefault retrieves the value of the current Nullable<(Of <(T>)>) object, or a default value, again on MSDN.
Application 2:
1: int? x = null;
2:
3: int y = x.GetValueOrDefault();
4:
5: if (x.GetValueOrDefault(-1) == 0)
6: {
7: Console.WriteLine("x is zero(0).");
8: }
Reflector 2:
1: int? x = null;
2: int y = x.GetValueOrDefault();
3: if (x.GetValueOrDefault(-1) == 0)
4: {
5: Console.WriteLine("x is zero(0).");
6: }
Application 2 and Reflector 2, both return the same result. Delving deeper into the code and examining the Nullable<T> class, you will find, 2 GetValueOrDefault overloaded methods. One method accepts no parameters, while the other accepts 1, T defaultValue. On line 3 and 5 of Application 2, you can see the differences between them.
GetValueOrDefault():
The value of the Value property if the HasValue property is true; otherwise, the default value of the current Nullable<> object. The type of the default value is the type argument of the current Nullable<> object, and the value of the default value consists solely of binary zeroes.
E.g int has a default value of 0 (zero) and, float has a default value of 0.0.
1: public T GetValueOrDefault()
2: {
3: return this.value;
4: }
GetValueOrDefault(-1):
Retrieves the value of the current Nullable<> object, or the specified default value.
Parameters
defaultValue
A value to return if the HasValue property is false.
Return Value
The value of the Value property if the HasValue property is true; otherwise, the defaultValue parameter.
1: public T GetValueOrDefault(T defaultValue)
2: {
3: if (!this.HasValue)
4: {
5: return defaultValue;
6: }
7: return this.value;
8: }
Using any of these will give the same result, but for code reading purposes using GetValueOrDefault with or without parameters will be the better option.