Gotchas when making use of Nullable<T> in C# 4 - c#

I've just started writing on a component where I found it might be useful to declare some of the properties nullable, instead of letting them resort to default values. However, I realized that I've never before used the non-nullable-type? syntax or the Nullable<T> type before, so there are probably some gotchas that'll soon jump out and bite me. So...
What are the biggest gotchas when using Nullable<T> and the shorthand ? syntax?
How do I work around them?
What are the biggest advantages/new possibilities that are made available to me when I start using them?

A common gotcha is attempting to assign to a nullable variable with a conditional expression as follows:
bool useDefault = true;
int defaultValue = 50;
int? y = useDefault ? defaultValue : null;
At first glance this might look like it should work but actually it gives a compile error:
Type of conditional expression cannot be determined because there is no
implicit conversion between 'int' and '<null>'
Solution: add a cast to one or both of the possible outcomes:
int? y = useDefault ? defaultValue : (int?)null;
Less commonly seen: Normally it is safe to assume that for integers a <= 5 and !(a > 5) are equivalent. This assumption is not true for nullable integers.
int? x = null;
Console.WriteLine(x <= 5);
Console.WriteLine(!(x > 5));
Result:
False
True
Solution: Handle the null case separately.
Here's another slight variation of the above:
int? y = null;
int? z = null;
Console.WriteLine(y == z);
Console.WriteLine(y <= z);
Output:
True
False
So y is equal to z, but it's not less than or equal to z.
Solution: Again, treating the null case separately can avoid surprises.

Something people are often surprised by is that there is no such thing as a boxed nullable value type. If you say:
int? x = 123;
int? y = null;
int z = 456;
object xx = x;
object yy = y;
object zz = z;
you might think that since zz contains a boxed int, that xx and yy contain boxed nullable ints. They do not. xx contains a boxed int. yy is set to null.

you can do .HasValue to check if the variable is null
you can do
myvar = nullablevar ?? defaultvalue; //will set defaultvalue if nullablevar is null
and more, it's not new to c# 4
read this for more information

Nullable<T> is a special value type. It might help if you understand how it actually works. There are a few subtle things about it that are not immediately obvious. I blogged about here.
Actual gotchas - not many. Just about the biggest one is that explicit cast might throw an InvalidOperationException (and not NullReferenceException). The compiler should guide you for any problems that might arise.

Nullable<T> types are a bit unusual; they are (strictly speaking) neither value nor reference types, but something strange in-between. Boxing/unboxing and typeof in particular have special rules so the results are less unexpected.
For details, I recommend Jon Skeet's book C# in Depth. If you don't already own it, you should. :)

One of the best uses is that it maps quite well to nullable database fields -- keeping that in mind, you want to use it as you would a null field in a database.
That is, a null value is not "other" -- it means unknown, or incalculable at this time, or that given other values in this object/record, it doesn't make sense for this to be a value. Your situation sounds like it is valid -- user preferences can be null, and actual values will be
actualValue = userValue ?? defaultValue;
The ?? is the null coalesce operator -- the above is equivalent to the following:
actualValue = userValue.HasValue ? userValue : defaultValue;
or
actualValue = (userValue != null) ? userValue : defaultValue;
The temptation I see people give into most often is using bool? as a tri-state flag. This doesn't make sense, because there is no third possibility in true/false/???. Others reading your code will have to dig through comments (best case scenario) to find out that true meant to use blue text, false meant red text, and null meant green text. Use enums for this.
That's the biggest trap I see people fall into -- other than that, just get used to checking if your nullables are null -- either through comparison to null or by using .HasValue

I am not currently using 4.0, but in 2.0 I have the problem that, like most Generics, int? can't be de-serialized easily. Perhaps 4.0 is smarter with Reflection, but the default XML serializer utilities can't read it of it is exposed. It is quite annoying.

Set default value unconsciously while using nullable. I have seen this a few times. Eg.
int? localVar = 0;
// do something ..
if (localVar.HasValue)
_myMemberValue = localVar.Value;
The localVar is never null because it was initialize with a value so the test for HasValue is alwasy true and _myMemberValue may incorrectly assigned with incorrect value.
-- Editied, to add more comments ----
Forgot to mention. One major advantage that I have seen is to use the field for representing Nullable field in database. This is also generated automatically if you use Linq and EF. But traditionally before Nullable, it is manual work and error prone to handle update of field and deciding on when to set it with a value or to null.

Related

C# Nullable<Enum> is being set a value of -1 when in code I'm setting it to null [duplicate]

This question already has answers here:
Is there a way to check if int is legal enum in C#?
(9 answers)
Closed 4 years ago.
pretext:
ChestType is an enum
public enum ChestType
{
COMMON,
GEMNGOLDCHEST,
GODLYCHEST,
ASSCHEST
}
slotAndChestIndex is a ChestType?[]
chestSlotsAndChestsSaved is an int[]
(Sorry for the bad names)
slotAndChestIndex[i] = (ChestType?)chestSlotsAndChestSaved[i] ?? null;
I believe the above line says:
"If I cant cast this int to a ChestType? then express it as null"
ChestType? is however being set to a value of -1 which seems weird to me.
Am I doing something wrong here? Event when I try set it to default(ChestType?) it still sets it to -1 lol. I thought the default of any Nullable type is null.
Please tell me what I'm not understanding!
You can't validate if it is defined within your enum that way; it'll just assign the value of your variable chestSlotsAndChestSaved[i] in it (even though it's -1 and it's not defined in your enum).
The way you can verify this is with:
slotAndChestIndex[i] = (ChestType?)(Enum.IsDefined(typeof(ChestType), chestSlotsAndChestSaved[i]) ? chestSlotsAndChestSaved[i] : (int?)null);
PS: I haven't tested the code, even though, Enum.IsDefined(typeof(ChestType), chestSlotsAndChestSaved[i]) is your way to go.
Neither the ?? operator nor the cast you're doing do quite what you think.
To start with, the cast you've used will never produce a null value - casting from an int to (most) enums will simply produce a value of the type of the enum, but potentially with a numeric value, not one of the enum members. The fact that you cast to ChestType? rather than ChestType doesn't change that. In addition, if a direct cast is performed like you've shown and can't be performed an exception will be raised, and the result will not be null. This should never happen for literal conversions like this, but could happen when casing between classes.
Next, the ?? operator, also known as the null-coalescing operator, evaluates to the left operand if the left operand is not null, and evaluates to the right operand if the left operand is null. So if chestSlotsAndChestSaved[i] was equal to null, the expression would become the right hand operand - however since the right operand is always null, that part of the expression effectively does nothing.
Overall, the most likely reason that slotAndChestIndex[i] is coming back as -1 is because chestSlotsAndChestSaved[i] is -1.

Using the Null Conditional Operator to check values on objects which might be null

I've been playing with C# 6's Null Conditional Operator (more info here).
I really like the syntax and I think it makes the code much more readable however I think it is questionable as to what exactly the code is going to do when you come across checking the value of a property on an object which itself might be null.
For example, if I had a class with a decimal property on it and I wanted a conditional check on the value of that decimal, I would write something like:
if (foo?.Bar > max)
{
// do something
}
On the surface this looks great... If foo is not null, get the value of Bar and check if it's greater than a maximum value, if it is, do something.
However, what if foo is null?!
This documentation about the new and improved features of C# 6 says something along these lines:
if in fact the value of the object is null, the null-conditional
operator will return null. It short-circuits the call to Bar, and
immediately returns null, avoiding the programming error that would
otherwise result in a NullReferenceException.
I've written a fiddle here which shows that it does indeed work and is doing what I'm expecting it to do however I can't get my head around how it is deciding the result of the condition.
How does the short-circuit equal a false? In my head this code is now going to say "If foo is null, check if null is > max, which is impossible, so return false" or "If foo is null, then foo != null will return false, so you get a false" however the documentation says the null conditional check returns null, not false.
How does the short-circuit equal a false?
if (foo?.Bar > max)
{
// do something
}
is roughly equivalent to:
Decimal? bar = null;
if (foo != null)
bar = foo.Bar;
if (bar > max)
{
// do something
}
Thus, the short circuit doesn't equal false. It equals a Decimal? (nullable Decimal) which is then compared to max.
See also: How does comparison operator works with null int?
It short-circuits the call to Bar
means stop checking the following steps (.) within an object reference chain if the parent is already null. This means operators like a comparison are not affected because you are using the value instead of moving in the chain. This behaviour is called null propagation. You can find some nice descriptions at Code Project or Dave Fancher.
Using the null conditional operator returns a nullable value like double?. This value is then compared with max. The behaviour of a null in such a comparision is well described by Microsoft:
When you perform comparisons with nullable types, if the value of one
of the nullable types is null and the other is not, all comparisons
evaluate to false except for != (not equal).
This means:
if (null > max)
{
//never called
}
The Null Conditional Operator should be used only for scenarios regarding objects properties's multiple assignments (see objects mapping, etc..) where it could be boring verify every time if occurs the null condition of the property.
Or also for scenarios like the following :
int? count = customers?[0]?.Orders?.Count(); // null if customers, the first customer, or Orders is null
Using this operator into an if test expression it could lead to unexpected behaviours, for example in your if statements case on fiddler you get a "passed" test (the last if statement) but with a null value, which is obviously not a valid case

The 'is' operator cannot be applied to an operand of a static type

What does this error mean in this context?
if (value == null)
return "";
if (value is Nullable && ((INullable)value).IsNull) //error on this line
return "";
if (value is DateTime)
{
if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
return ((DateTime)value).ToString ("yyyy-MM-dd");
return ((DateTime)value).ToString ("yyyy-MM-dd HH:mm:ss");
}
I searched but didn't get any information on this error. I am trying this on Mono (2.10.8.1). This is a project actually meant for Windows, but when I tried to compile it in Monodevelop, I got this error.
The problem is here:
if (value is Nullable
It thinks you're talking about the static class System.Nullable rather than the System.Nullable<T> struct.
Perhaps you meant:
if (value is INullable ...)
?
Note that if value is of compile-time type object, then it will never be a Nullable<T>, as boxing a null value would give a null reference, and boxing a non-null value would give a boxed value of the underlying type.
If you think there's still something else which you need to achieve, please specify what you're trying to do.
The type System.Nullable is a static type--which means an instance can't be created. Therefore value can never be a type of Nullable.
The Microsoft C# compiler doesn't have this error--so, anyone using Visual Studio won't get this error. So, the people who created RedditSaveTransfer seem to have used Visual Studio. Compiling the same in MonoDevelop obviously has this extra error.
I don't know anything about this code, so I don't know the intention of what they're trying to do here. Clearly value can never be of type Nullable, so the whole if statement will always be false. So, I assume, it would be safe to simply remove the block from the code.
But, based on the code it looks like it's trying to check if the value is some sort of SqlTypes.INullable. In which case I might do something like:
INullable nullable = value as INullable;
if(nullable != null && nullable.IsNull)
return "";
But, that will produce different results than the original code; and I don't know if that's a good thing or a bad thing.
I agree with Jon that possibly this was a typo for value is INullable; but, I don't know for sure.

Why does the == operator work for Nullable<T> when == is not defined?

I was just looking at this answer, which contains the code for Nullable<T> from .NET Reflector, and I noticed two things:
An explicit conversion is required when going from Nullable<T> to T.
The == operator is not defined.
Given these two facts, it surprises me that this compiles:
int? value = 10;
Assert.IsTrue(value == 10);
With the code value == 10, either value is being magically converted to an int (hence allowing int's == operator to be used, or the == operator is being magically defined for Nullable<int>. (Or, I presume less likely, Reflector is leaving out some of the code.)
I would expect to have to do one of the following:
Assert.IsTrue((value.Equals(10)); // works because Equals *is* defined
Assert.IsTrue(value.Value == 10); // works because == is defined for int
Assert.IsTrue((int?)value == 10); // works because of the explicit conversion
These of course work, but == also works, and that's the part I don't get.
The reason I noticed this and am asking this question is that I'm trying to write a struct that works somewhat similarly to Nullable<T>. I began with the Reflector code linked above, and just made some very minor modifications. Unfortunately, my CustomNullable<T> doesn't work the same way. I am not able to do Assert.IsTrue(value == 10). I get "Operator == cannot be applied to operands of type CustomNullable<int> and int".
Now, no matter how minor the modification, I would not expect to be able to do...
CustomNullable<T> value = null;
...because I understand that there is some compiler magic behind Nullable<T> that allows values to be set to null even though Nullable<T> is a struct, but I would expect I should be able to mimic all the other behaviors of Nullable<T> if my code is written (almost) identically.
Can anyone shed light on how the various operators of Nullable<T> work when they appear not to be defined?
Given these two facts, it surprises me that this compiles
Given only those two facts, that is surprising.
Here's a third fact: in C#, most operators are 'lifted to nullable'.
By "lifted to nullable", I mean that if you say:
int? x = 1;
int? y = 2;
int? z = x + y;
then you get the semantics of "if either x or y is null then z is null. If both are not null then add their values, convert to nullable, and assign the result to z."
The same goes for equality, though equality is a bit weird because in C#, equality is still only two-valued. To be properly lifted, equality ought to be three-valued: x == y should be null if either x or y is null, and true or false if x and y are both non-null. That's how it works in VB, but not in C#.
I would expect I should be able to mimic all the other behaviors of Nullable<T> if my code is written (almost) identically.
You are going to have to learn to live with disappointment because your expectation is completely out of line with reality. Nullable<T> is a very special type and its magical properties are embedded deeply within the C# language and the runtime. For example:
C# automatically lifts operators to nullable. There's no way to say "automatically lift operators to MyNullable". You can get pretty close by writing your own user-defined operators though.
C# has special rules for null literals -- you can assign them to nullable variables, and compare them to nullable values, and the compiler generates special code for them.
The boxing semantics of nullables are deeply weird and baked into the runtime. There is no way to emulate them.
Nullable semantics for the is, as and coalescing operators are baked in to the language.
Nullables do not satisfy the struct constraint. There is no way to emulate that.
And so on.
Well, if you can use reflector why don't you compile this code:
int? value = 10;
Console.WriteLine(value == 10);
and then open it in reflector? You'll see this (make sure to select 'None' as .net version to decompile to):
int? value;
int? CS$0$0000;
&value = new int?(10);
CS$0$0000 = value;
Console.WriteLine((&CS$0$0000.GetValueOrDefault() != 10) ? 0 : &CS$0$0000.HasValue);
So basically the compiler does the heavy lifting for you. It understands what '==' operation means when used with nullables and compiles the necessary checks accordingly.
This is language dependent. C# and Visual Basic emit different code when dealing with operators on nullable value types. To udnerstand it you need to look at the actual IL code.
Nullable<T> has this method:
public static implicit operator T?(T value)
{
return new T?(value);
}
It looks like there is an implicit conversion from it 10 to Nullable<int> 10
To make == / != work for you. You can add
public static bool operator ==(MyNullable<T> left, MyNullable<T> right) {}
// together with:
public static implicit operator MyNullable<T>(T value) {}
should give you support for myNullable == 10 operation
Because the compiler converts Nullable<T> to T and then performs the comparison.

Operator '=' chaining in C# - surely this test should pass?

I was just writing a property setter and had a brain-wave about why we don't have to return the result of a set when a property might be involved in operator = chaining, i.e:
var a = (b.c = d);
(I've added the brackets for clarity - but it makes no difference in practise)
I started thinking - where does the C# compiler derive the value that is assigned to a in the above example?
Logic says that it should be from the result of the (b.c = d) operation but since that's implemented with a void set_blah(value) method it can't be.
So the only other options are:
Re-read b.c after the assignment and use that value
Re-use d
Edit (since answered and comments from Eric) - there's a third option, which is what C# does: use the value written to b.c after any conversions have taken place
Now, to my mind, the correct reading of the above line of code is
set a to the result of setting b.c to d
I think that's a reasonable reading of the code - so I thought I'd test whether that is indeed what happens with a slightly contrived test - but ask yourself if you think it should pass or fail:
public class TestClass
{
private bool _invertedBoolean;
public bool InvertedBoolean
{
get
{
return _invertedBoolean;
}
set
{
//don't ask me why you would with a boolean,
//but consider rounding on currency values, or
//properties which clone their input value instead
//of taking the reference.
_invertedBoolean = !value;
}
}
}
[TestMethod]
public void ExampleTest()
{
var t = new TestClass();
bool result;
result = (t.InvertedBoolean = true);
Assert.IsFalse(result);
}
This test fails.
Closer examination of the IL that is generated for the code shows that the true value is loaded on to the stack, cloned with a dup command and then both are popped off in two successive assignments.
This technique works perfectly for fields, but to me seems terribly naive for properties where each is actually a method call where the actual final property value is not guaranteed to be the input value.
Now I know many people hate nested assignments etc etc, but the fact is the language lets you do them and so they should work as expected.
Perhaps I'm being really thick but to me this suggests an incorrect implementation of this pattern by the compiler (.Net 4 btw). But then is my expectation/reading of the code incorrect?
The result of an assignment x = {expr} is defined as the value evaluated from {expr}.
ยง14.14.1 Simple assignment (ECMA334 v4)
...
The result of a simple assignment expression is the value assigned to
the left operand. The result has the same type as the left operand,
and is always classified as a value.
...
And note that the value assigned is the value already evaluated from d. Hence the implementation here is:
var tmp = (TypeOfC)d;
b.c = tmp;
a = tmp;
although I would also expect with optimisations enabled it will use the dup instruction rather than a local variable.
I find it interesting that your expectation is that the crazy assignment -- that is, assigning two different values because one of them is an extremely weird property with unusual behaviour -- is the desirable state of affairs.
As you've deduced, we do everything in our power to avoid that state. That is a good thing. When you say "x = y = z" then if at all possible we should guarantee that x and y end up assigned the same value -- that of z -- even if y is some crazy thing that doesn't hold the value you give it. "x = y = z" should logically be like "y = z, x = z", except that z is only evaluated once. y doesn't come into the matter at all when assigning to x; why should it?
Also, of course when doing "x = y = z" we cannot consistently "reuse" y because y might be a write only property. What if there is no getter to read the value from?
Also, I note that you say "this works for fields" -- not if the field is volatile it doesn't. You have no guarantee whatsoever that the value you assigned is the value that the field takes on if it is a volatile field. You have no guarantee that the value you read from a volatile field in the past is the value of the field now.
For more thoughts on this subject, see my article:
http://blogs.msdn.com/b/ericlippert/archive/2010/02/11/chaining-simple-assignments-is-not-so-simple.aspx
The assignment operator is documented to return the result of evaluating its second operand (in this case, b). It doesn't matter that it also assigns this value to its first operand, and this assignment is done by calling a method that returns void.
The spec says:
14.14.1 Simple assignment
The = operator is called the simple assignment operator. In a simple assignment, the right operand shall
be an expression of a type that is implicitly convertible to the type
of the left operand. The operation assigns the value of the right
operand to the variable, property, or indexer element given by the
left operand. The result of a simple assignment expression is the
value assigned to the left operand. The result has the same type as
the left operand, and is always classified as a value.
So actually what happens is:
d is evaluated (let's call the value produced val)
the result is assigned to b.c
the assignment operator's result is val
a is assigned the value val
the second assignment operator's result is also val (but since the whole expression ends here, it goes unused)

Categories