Why isn't null an instance of a Nullable<> type? - c#

While writing tests that involved manual type checking I came across the fact that null does not evaluate as an instance of Nullable<> types, e.g. for the type Nullable<int> (which is the same as int?) the following statement is false
null is int?
while assigning null to int? is valid. Why is this so?

Well, why should nullables be special? This doesn't stand for any reference type, period:
var isObject = null is object;
Will give you a compile time error:
Error CS0184: The given expression is never of the provided ('object') type
Nullable<T> is a red herring here.
The type of null is the null type and its assignable to any reference type or nullable type because there is an implicit conversion (§2.4.4.6).
This is operator according to the spec works the following way (§7.10.10):
The is operator is used to dynamically check if the run-time type of an object is compatible with a given type. The result of the operation E is T, where E is an expression and T is a type, is a boolean value indicating whether E can successfully be converted to type T by a reference conversion, a boxing conversion, or an unboxing conversion. The operation is evaluated as follows, after type arguments have been substituted for all type parameters:
If E is an anonymous function, a compile-time error occurs
If E is a method group or the null literal, or if the type of E is a reference type or a nullable type and the value of E is null, the result is false. (...)
Bolded part for clarification.
Read this and this answer for more info.

What may be confusing is that null can be a value and a type.
If you compare or assign null the following implicit conversion is used to first convert the value to a Nullable.
public static implicit operator Nullable<T> (
T value
)
If you are using is not a value but a type comparison will be done. As null is of type null and not Nullable<T> they aren't equal.

In sort:-by making any value type nullable,null wont get converted to that type or null is not of that type.In case of nullable if the variable is assigned to null, HasValue property of sturct becomes false and then boxing will return reference for null but it doesn't mean it is of that particular value type.
you need to look into implementation and working of
Nullable<T>
Fundamental Properties
The two fundamental members of the Nullable structure are the HasValue and Value properties. If the HasValue property for a Nullable object is true, the value of the object can be accessed with the Value property. If the HasValue property is false, the value of the object is undefined and an attempt to access the Value property throws an InvalidOperationException.
Boxing and Unboxing
When a nullable type is boxed, the common language runtime automatically boxes the underlying value of the Nullable object, not the Nullable object itself. That is, if the HasValue property is true, the contents of the Value property is boxed. When the underlying value of a nullable type is unboxed, the common language runtime creates a new Nullable structure initialized to the underlying value.
If the HasValue property of a nullable type is false, the result of a boxing operation is null. Consequently, if a boxed nullable type is passed to a method that expects an object argument, that method must be prepared to handle the case where the argument is null. When null is unboxed into a nullable type, the common language runtime creates a new Nullable structure and initializes its HasValue property to false.
i have just copied this line from Microsoft docs it will give you some idea about hole concept
for reading entire documentation link is bellow
https://learn.microsoft.com/en-us/dotnet/api/system.nullable-1?view=netframework-4.7

Related

Type int? vs type int

I've this comparison which equals false as expected
bool eq = typeof(int?).Equals(typeof(int));
now I have this code
List<object> items = new List<object>() { (int?)123 };
int result = items.OfType<int>().FirstOrDefault();
but this returns 123 - anyway that value is of type int?
How can this be?
Nullable types have special "boxing" rules; "boxing" is when a value-type is treated as object, as per your code. Unlike regular value-types, a nullable value-type is boxed either as null (regular null, no type), or as the non-nullable type (the T in T?). So: an int? is boxed as an int, not an int?. Then when you use OfType<int>() on it, you get all the values that are int, which is: the single value you passed in, since it is of type int.
A nullable value type is boxed by the following rules
If HasValue returns false, the null reference is produced.
If HasValue returns true, a value of the underlying value type T is
boxed, not the instance of nullable.
In your example second rule has been followed as you have value:
var i = (object)(int?)123;
It is a bit late, but beside of Marc's answer to your question, I want to give some additional information about Nullable value types in CLR.
The CLR has built-in support for nullable value types. This special support is provided for boxing, unboxing, calling GetType, calling interface methods.
For example, let's check GetType():
Int32? x = 5;
Console.WriteLine(x.GetType());
What you think it will print to the console?
System.Nullable<Int32? Not, the result is System.Int32.
Or, let's check boxing, which you noted in your question:
Int32? n =5;
Object o = n;
Console.WriteLine("o's type={0}", o.GetType()); // "System.Int32"
The rule is that:
When the CLR is boxing a Nullable instance, it checks to see if it
is null, and if so, the CLR doesn’t actually box anything, and null is
returned. If the nullable instance is not null, the CLR takes the
value out of the nullable instance and boxes it. In other words, a
Nullable with a value of 5 is boxed into a boxed-Int32 with a
value of 5.
And, at the end I want to explain how CLR add special support for calling interface methods from Nullable Types.
Let's take a look to that:
Int32? n = 5;
Int32 result = ((IComparable) n).CompareTo(5); // Compiles & runs OK
Console.WriteLine(result); // 0
In the preceding code, I’m casting n, a Nullable<Int32>, to IComparable<Int32>, an interface
type. However, the Nullable<T> type does not implement the IComparable<Int32> interface as
Int32 does. The C# compiler allows this code to compile anyway.

Evaluating "null == <int>" [duplicate]

This question already has answers here:
C# okay with comparing value types to null
(11 answers)
Closed 4 years ago.
This statement seems to work, but I'm not sure exactly how
int id = 0; // non-nullable ("primative"/value-type/struct)
_list?.Find(t => { return t?.Id == id; })?.DeptId ?? 0;
If t is null, then t?.Id is null, correct?
Then how is this legal:
null == id
Update (5/8/18)
The statement in visual studio
if (null == 0) {}
Gets highlighted green and upon inspection with a mouse over states
"The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type 'int?'
Update (5/24/18)
Nullable<T> Struct
Fundamental Properties
The two fundamental members of the Nullable structure are the
HasValue and Value properties. If the HasValue property for a
Nullable object is true, the value of the object can be accessed
with the Value property. If the HasValue property is false, the value
of the object is undefined and an attempt to access the Value property
throws an InvalidOperationException.
Boxing and Unboxing
When a nullable type is boxed, the common language runtime
automatically boxes the underlying value of the Nullable object,
not the Nullable object itself. That is, if the HasValue property
is true, the contents of the Value property is boxed. When the
underlying value of a nullable type is unboxed, the common language
runtime creates a new Nullable structure initialized to the
underlying value.
If the HasValue property of a nullable type is false, the result of a
boxing operation is null. Consequently, if a boxed nullable type is
passed to a method that expects an object argument, that method must
be prepared to handle the case where the argument is null. When null
is unboxed into a nullable type, the common language runtime creates a
new Nullable structure and initializes its HasValue property to
false.
ref:
https://learn.microsoft.com/en-us/dotnet/api/system.nullable-1?view=netframework-4.7.2
From the C# 5.0 spec (Section 7.3.7 Lifted operators):
For the equality operators
== !=
a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is bool. The lifted form is constructed by adding a single ? modifier to each operand type. The lifted operator considers two null values equal, and a null value unequal to any non-null value. If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce the bool result.
Thus, the lifted operator int? == int? is used. Since the left-hand side is null and the right-hand side isn't, the operator returns false.

GetType on Nullable Boolean

I was looking into nullable bools when I found this article on Microsoft MSDN
How to: Identify a Nullable Type (C# Programming Guide)
You can use the C# typeof operator to create a Type object that represents a Nullable type.
So I tried checking with a nullable bool:
Console.Write(typeof(bool?)); //System.Nullable`1[System.Boolean]
The article on MSDN says
You can also use the classes and methods of the System.Reflection namespace to generate Type objects that represent Nullable types. However, if you try to obtain type information from Nullable variables at runtime by using the GetType method or the is operator, the result is a Type object that represents the underlying type, not the Nullable type itself.
Calling GetType on a Nullable type causes a boxing operation to be performed when the type is implicitly converted to Object. Therefore GetType always returns a Type object that represents the underlying type, not the Nullable type.
If this is true I expect to get the same result from .GetType() whether I use a nullable bool or a regular bool. But this is not what happens:
bool a = new bool();
Console.Write(a.GetType()); //Prints System.Boolean
bool? b = new bool?();
Console.Write(b.GetType()); //Exception!
The exception that occured:
An unhandled exception of type 'System.NullReferenceException' occurred in BoolTest.exe
Additional information: Object reference not set to an instance of an object.
But the object reference is set to an instance of an object. What could be the cause of this error?
Your actual question seems to be:
By initializing a Nullable<T> to its default value using its default constructor, for example bool? b = new bool?();, why does accessing b's members such as GetType() throw a NullReferenceException? Doesn't new always return a value, so b can't really be null?
Well, yes and no. Nullable<T> is kind of special. From the C# specs:
4.1.10 Nullable types
[...]
An instance of a nullable type T? has two public read-only properties:
A HasValue property of type bool
A Value property of type T
An instance for which HasValue is true is said to be non-null. A non-null instance contains a known value and Value returns that value.
An instance for which HasValue is false is said to be null. A null instance has an undefined value. Attempting to read the Value of a null instance causes a System.InvalidOperationException to be thrown.
So yes, bool? b = new bool?(); does return an instance: one you only can call HasValue on. Since it returns false, you can't do much else with that instance.
Then the next relevant section:
4.3.1 Boxing conversions
Boxing a value of a nullable-type produces a null reference if it is the null value (HasValue is false)
This is also explained in MSDN: Boxing Nullable Types (C# Programming Guide):
Objects based on nullable types are only boxed if the object is non-null. If HasValue is false, the object reference is assigned to null instead of boxing.
Somewhat further into the specs:
11.3.5 Boxing and unboxing
When a struct type overrides a virtual method inherited from System.Object (such as Equals, GetHashCode, or ToString), invocation of the virtual method through an instance of the struct type does not cause boxing to occur.
GetType() is not overridden by Nullable<T>, so boxing will occur. When you call GetType() or any non-overridden method on a struct, the struct will be boxed to an object before calling that method. In the case of a null Nullable<T>, the result of that boxing operation will be (object)null. Hence the exception.
See also Does calling a method on a value type result in boxing in .NET?.
So, to answer your question:
b is not null, it holds a Nullable<bool> with a HasValue indicating false.
Calling the non-overridden GetType() method on it, causes the Nullable<bool> struct to be boxed in order to access the underlying method object.GetType().
This boxing operation actually doesn't box, but simply returns (object)null.
In the end, you're calling ((object)null).GetType(), which throws the NullReferenceException you encounter.
If you're actually looking for a piece of code that can return the type of any variable, even a null Nullable<T>, use something like this:
Type GetType<T>(T obj)
{
return typeof(T);
}
Which you can then call like this:
Console.WriteLine(GetType(b));
You're calling GetType on a NULL Reference (The result of boxing a Nullable Type with No Value).
bool? b = new bool?(); is equivalent to bool? b = null;
Try this to get the correct result:
bool? b = new bool?(false);
Console.Write(b.GetType()); // System.Boolean
The documentation means that if you call GetType() successfully on a Nullable object that has value (Not Null). You get the Underlying type which is System.Boolean. But you can't call any method using a NULL reference and this is a general rule that applying to any reference type.
To clear the equivalence point between = null and new bool?(), check this Fiddle. Both generates the same IL:
IL_0001: ldloca.s V_0
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<bool>
and
IL_0009: ldloca.s V_1
IL_000b: initobj valuetype [mscorlib]System.Nullable`1<bool>

Difference between Nullable types "not having a value" and "being Null" in C#

What is the difference in the terms
Not having a value
and
2.Being Null
in Nullable types in C#.
In otherwords when do we say a type does not have a value and when do we say the value is null.
Nullable<T> is a struct, and being a struct, it cannot ever actually be null. The only actual data stored in a Nullable<T> is an underlying value of type T and a boolean HasValue flag. A Nullable<T> value in which HasValue is false can be thought of as being null, even though it technically is not null.
There is some compiler magic such that someNullable == null can be called, and the result of that expression is actually the same as someNullable.HasValue. You can also assign null to a Nullable<T>. What this will actually do is create a new Nullalbe<T> struct where HasValue is false. (Interestingly, it's not possible for you to do that yourself if you were to write your own type.)
There is some more compiler magic such that if you box a Nullalbe<T> it doesn't actually box the nullable type. If HasValue is actually true then it will pull out the underlying value and box that. If HasValue is false then it will just box null. When unboxing something to a Nullable it then does the reverse; creating a Nullable<T> struct based on whether it's null or not. (This is another thing that you couldn't do with a custom type.)
Because of these special compiler features it does a fairly good job of making it appear as if Nullable can actually be null, but the reality is that it is not actually null.
A Nullable<T> itself cannot be null because its a structure. So you may find a Nullable<T> that follow the case: Not having a value but it is not null actually.
EDIT:
---------------------------- Not Having a Value case ------- Can be null case
Reference types ----(equals to can be null case)-------- Possible
Value types------------ Not Possible ---------------------------Not Possible
Nullable-----------------Possible --------------------------------Not Possible
Here, the sepration of Nullable and Value types do not mean Nullable is not a value type.
It's been mentioned that the generic nullable type, Nullable<T> (where T must be a value type) has the important properties:
bool HasValue // Indicating that a real value is present, or if the instance should be considered null
T Value // Your value, if present. (non-nullable)
So you could conceivably have these cases for a Nullable<int> myInt:
HasValue | Value | Represents
------------------------------
false | 0 | No Value / null
true | 0 | 0
true | 3 | 3
In the first case, HasValue indicates that the myInt has no value, and represents the null state; a comparison for equality with the null literal will be considered true:
(myInt == null) // true.
The nullable type itself will not actually be null (it's a struct, it can't be), but the compiler will resolve the the null comparison by querying HasValue, as mentioned in one of the other answers linked.
If we are discussing terms, let's be clear with language. As many of the other answers have said, in c#, when a non-nullable type is made to be nullable using the ? operator, it becomes the Nullable struct, where T will always be a value type.
Ref: http://msdn.microsoft.com/en-us/library/b3h38hb0(v=vs.110).aspx
see Servy's answer for a good explanation of this.
However, once any type is nullable (regardless of if it is a reference type or has been made to use the Nullable struct) it would be correct to say that if the type has no value, the type is null, and vice versa. From the above Microsoft documentation:
A type is said to be nullable if it can be assigned a value or can be
assigned null, which means the type has no value whatsoever.

Is there a technical reason for no implicit conversion from DBNull to nullable types?

Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
Is there a technical reason why there is no implicit conversion from DBNull to the various nullable and/or sql types? I understand why the conversions don't currently happen, but don't understand why an implicit conversion wasn't created at the time or added in subsequent versions of the framework.
Just to be clear, I'm looking for technical reasons, not "because that's they way they did it" or "I like it that way".
The most straightforward explanation comes from Microsoft's documentation:
CLR nullable types are not intended for storage of database nulls because an ANSI SQL null does not behave the same way as a null reference (or Nothing in Visual Basic).
Well, I don't know about the SqlTypes case, but there definitely are some technical reasons why adding an implicit conversion between DBNull.Value and values of Nullable<T> with HasValue = false wouldn't work.
Remember, DBNull is a reference type, and despite the fact that Nullable<T> acts like a reference type -- by pretending to be able to take on the null value -- it's actually a value type, with value semantics.
In particular, there's a weird edge case when values of type Nullable<T> are boxed. The behavior is special-cased in the runtime to box values of type Nullable<T> to a boxed version of T, not a boxed version of Nullable<T>.
As the MSDN documentation explains it:
When a nullable type is boxed, the common language runtime automatically boxes the underlying value of the Nullable(Of T) object, not the Nullable(Of T) object itself. That is, if the HasValue property is true, the contents of the Value property is boxed. When the underlying value of a nullable type is unboxed, the common language runtime creates a new Nullable(Of T) structure initialized to the underlying value.
If the HasValue property of a nullable type is false, the result of a boxing operation is Nothing. Consequently, if a boxed nullable type is passed to a method that expects an object argument, that method must be prepared to handle the case where the argument is Nothing. When Nothing is unboxed into a nullable type, the common language runtime creates a new Nullable(Of T) structure and initializes its HasValue property to false.
Now we get into a tricky problem: the C# language spec (§4.3.2) says we can't use an unboxing conversion to convert DBNull.Value into Nullable<T>:
For an unboxing conversion to a given nullable-type to succeed at run-time, the value of the source operand must be either null or a reference to a boxed value of the underlying non-nullable-value-type of the nullable-type. If the source operand is a reference to an incompatible object, a System.InvalidCastException is thrown.
And we can't use a user-defined conversion to convert from object to Nullable<T>, either, according to §10.10.3:
It is not possible to directly redefine a pre-defined conversion. Thus, conversion operators are not allowed to convert from or to object because implicit and explicit conversions already exist between object and all other types.
OK, you or I couldn't do it, but Microsoft could just amend the spec, and make it legal, right? I don't think so.
Why? Well, imagine the intended use case: you've got some method that is specified to return object. In practice, it either returns DBNull.Value or int. But how could the compiler know that? All it knows is that the method is specified to return object. And the conversion operator to be applied must be selected at compile time.
OK, so assume that there is some magical operator that can convert from object to Nullable<T>, and the compiler has some way of knowing when it is applicable. (We don't want it to used for every method that is specified to return object -- what should it do if the method actually returns a string?) But we still have an issue: the conversion could be ambiguous! If the method returns either long, or DBNull.Value, and we do int? v = Method();, what should we do when the method returns a boxed long?
Basically, to make this work as intended, you'd have to use the equivalent of dynamic to determine the type at runtime and convert based on the runtime type. But then we've broken another rule: since the actual conversion would only be selected at runtime, there's no guarantee that it would actually succeed. But implicit conversions are not supposed to throw exceptions.
So at this point, it's not only a change to the specified behavior of the language, a potentially significant performance hit, and on top of that it could throw an unexpected exception! That seems like a pretty good reason not to implement it. But if you need one more reason, remember that every feature starts out minus 100 points.
In short: what you really want here can't be done with an implicit conversion anyway. If you want the behavior of dynamic, just use dynamic! This does what you want, and is already implemented in C# 4.0:
object x = 23;
object y = null;
dynamic dx = x;
dynamic dy = y;
int? nx = (int?) dx;
int? ny = (int?) dy;
Console.WriteLine("nx.HasValue = {0}; nx.Value = {1}; ny.HasValue = {2};",
nx.HasValue, nx.Value, ny.HasValue);

Categories