In C#, what is the default value of a class instance variable of type int??
For example, in the following code, what value will MyNullableInt have if it is never explicitly assigned?
class MyClass
{
public int? MyNullableInt;
}
(It seems likely that the answer is almost certainly either null or 0, but which of those is it?)
The default value for int? -- and for any nullable type that uses the "type?" declaration -- is null.
Why this is the case:
int? is syntactic sugar for the type Nullable<T> (where T is int), a struct. (reference)
The Nullable<T> type has a bool HasValue member, which when false, makes the Nullable<T> instance "act like" a null value. In particular, the Nullable<T>.Equals method is overridden to return true when a Nullable<T> with HasValue == false is compared with an actual null value.
From the C# Language Specification 11.3.4, a struct instance's initial default value is all of that struct's value type fields set to their default value, and all of that struct's reference type fields set to null.
The default value of a bool variable in C# is false (reference). Therefore, the HasValue property of a default Nullable<T> instance is false; which in turn makes that Nullable<T> instance itself act like null.
I felt important to share the Nullable<T>.GetValueOrDefault() method which is particularly handy when working with math computations that use Nullable<int> aka int? values. There are many times when you don't have to check HasValue property and you can just use GetValueOrDefault() instead.
var defaultValueOfNullableInt = default(int?);
Console.WriteLine("defaultValueOfNullableInt == {0}", (defaultValueOfNullableInt == null) ? "null" : defaultValueOfNullableInt.ToString());
var defaultValueOfInt = default(int);
Console.WriteLine("defaultValueOfInt == {0}", defaultValueOfInt);
Console.WriteLine("defaultValueOfNullableInt.GetValueOrDefault == {0}", defaultValueOfNullableInt.GetValueOrDefault());
var x = default (int?);
Console.WriteLine("x == {0}", (x == null) ? "null" : x.ToString());
Related
I have Type and I want to get the default value. For example, if Type is class or nullable I should get null. But if it is integer, DateTime. decimal, ... I should get 0. What is the best way of doing this?
From your description you can just use a default expression or literal.
int a = default(int);
int a = default;
Default values of C# types (C# reference)
Type
Default value
Any reference type
null
Anybuilt-in integral numeric type
0 (zero)
Any built-in floating-point numeric type
0 (zero)
bool
false
char
'\0' (U+0000)
enum
The value produced by the expression (E)0, where E is the enum identifier.
struct
The value produced by setting all value-type fields to their default values and all reference-type fields to null.
Any nullable value type
An instance for which the HasValue property is false and the Value property is undefined. That default value is also known as the null value of a nullable value type.
I expect you can use something like this:
public static object GetDefaultValue(Type type)
{
return type.IsClass ? null : Activator.CreateInstance(type);
}
Try it online
You could use Activator.CreateInstance to generate an empty variable of the type and then check the value of it :)
Can someone explain why is it possible to call methods on null instance?
int? num = null;
var s1 = num.ToString();
var s2 = num.HasValue;
var s3 = num.GetHashCode();
var s4 = num.GetValueOrDefault();
var s5 = num.Value; // InvalidOperationException
var s6 = num.GetType(); // NullReferenceException
I can check the num is null in a debug mode, so how is it possible that ToString method or HasValue getter can be called on null instance, but for Value and GetType it is not possible? All of them are methods or properties on Nullable<> type or not?
I would naturally expect the Value getter returns null value, similarly as the HasValue returns false. I would expect too, that GetType returns Nullable<int> type info, or num is int? or num is Nullable<int> works. Why doesn't it work? How can I check the num is a nullable type?
Creating an instance doesn't change anything on that:
Nullable<int> num = new Nullable<int>();
What's behind the scene?
Nullable<T> has a bit of compiler magic that makes it appear as if there was a null value. But there isn't. Basically, since Nullable<T> is a value type, it cannot be null to begin with. Its nullability is determined whether there is a value or not. This means that you can call HasValue (which is important, since that's what the compiler inserts when you write num == null) and other methods that don't depend on a value being present.
As for a few specific points:
ToString is an implementation that works similar to how null values are converted to string when used in string concatenation, i.e. resulting in an empty string. You also don't really want ToString to ever throw.
GetHashCode is necessary to put Nullable<T> as a key in a dictionary, or place them into a hashset. It also should not throw, so it has to return something sensible when there's no value.
The documentation explains a bit of the underlying concepts.
Accessing the value when there isn't one is forbidden, though. As Zohar Peled and Marc Gravell ♦ note in the comments, this is what implicitly happens when calling GetType:
It would seem logical that the compiler could just silently replace nullableValue.GetType() with typeof(SomeT?), but that would then mean that it always gives confusing answers when compared to
object obj = nullableValue;
Type type = obj.GetType()
You would expect this to work similarly, but obj.GetType() will always return either typeof(T) (not typeof(T?)), or throw a NullReferenceException because T? boxes to either a T or to null (and you can't ask a null what type it is)
The mapping of constructs the compiler handles specially is more of less the following:
num == null → !num.HasValue
num != null → num.HasValue
num = null → num = new Nullable<int>()
num = 5 → num = new Nullable<int>(5)
(int) num → num.Value
(object) num → (object) num.Value // if HasValue
→ (object) null // if !HasValue
There's additional support for operators, most importantly comparison operators with non-nullable Ts and the various operators that work on potential null values like ??, but that's the gist of it.
Not really an answer, but just a note. You write:
I would naturally expect the Value getter returns null value
No! The very reason that Nullable<T> exists is to protect you from getting null values without checking first.
I was just wondering why the following code doesn't work (please keep in mind that I set age to be nullable):
myEmployee.age = conditionMet ? someNumber : null;
Yet the following works fine:
if(conditionMet)
{
myEmployee.age = someNumber;
}
else
{
myEmployee.age = null;
}
Why can't I set the value to null in a conditional operator?? All these if statements in my code is not nice.
Thanks.
The types on both sides have to be the same (or be implicitly convertible):
myEmployee.age = conditionMet ? someNumber : (int?)null;
From the docs:
Either the type of first_expression and second_expression must be the
same, or an implicit conversion must exist from one type to the other.
You can, just be clear about the type that null should be interpreted as:
myEmployee.age = conditionMet ? someNumber : (int?)null;
Look at what the documentation has to say:
[MSDN] The default value for a nullable type variable sets HasValue to false. The Value is undefined.
The default is thus null. Which means that you can simply do:
if (conditionMet)
myEmployee.age = someNumber;
There is no need for more obscure code syntax.
If required you can initialize it with null in advance, if it somehow was not the default, like so:
myEmployee.age = null;
if (conditionMet)
myEmployee.age = someNumber;
The types of the parts of the ternary statement must be implicitly castable to a common base. In the case of int and null, they aren't. You can solve this by making age a Nullable<int> (or int?) and casting someNumber to int?.
EDIT to clarify: you can set the value to null with a ternary statement with proper casting. The problem here isn't that you're trying to set a value to null with a ternary statement. It's that the compiler-inferred return types of the two expressions involved in the ternary statement cannot be implicitly casted to a common base type.
Typically the main use of the question mark is for the conditional, x ? "yes" : "no".
But I have seen another use for it but can't find an explanation of this use of the ? operator, for example.
public int? myProperty
{
get;
set;
}
It means that the value type in question is a nullable type
Nullable types are instances of the System.Nullable struct. A
nullable type can represent the correct range of values for its
underlying value type, plus an additional null value. For example, a
Nullable<Int32>, pronounced "Nullable of Int32," can be assigned any
value from -2147483648 to 2147483647, or it can be assigned the null
value. A Nullable<bool> can be assigned the values true, false, or
null. The ability to assign null to numeric and Boolean types is
especially useful when you are dealing with databases and other data
types that contain elements that may not be assigned a value. For
example, a Boolean field in a database can store the values true or
false, or it may be undefined.
class NullableExample
{
static void Main()
{
int? num = null;
// Is the HasValue property true?
if (num.HasValue)
{
System.Console.WriteLine("num = " + num.Value);
}
else
{
System.Console.WriteLine("num = Null");
}
// y is set to zero
int y = num.GetValueOrDefault();
// num.Value throws an InvalidOperationException if num.HasValue is false
try
{
y = num.Value;
}
catch (System.InvalidOperationException e)
{
System.Console.WriteLine(e.Message);
}
}
}
It is a shorthand for Nullable<int>. Nullable<T> is used to allow a value type to be set to null. Value types usually cannot be null.
In
x ? "yes" : "no"
the ? declares an if sentence. Here: x represents the boolean condition; The part before the : is the then sentence and the part after is the else sentence.
In, for example,
int?
the ? declares a nullable type, and means that the type before it may have a null value.
it declares that the type is nullable.
practical usage:
public string someFunctionThatMayBeCalledWithNullAndReturnsString(int? value)
{
if (value == null)
{
return "bad value";
}
return someFunctionThatHandlesIntAndReturnsString(value);
}
int? is shorthand for Nullable<int>. The two forms are interchangeable.
Nullable<T> is an operator that you can use with a value type T to make it accept null.
In case you don't know it: value types are types that accepts values as int, bool, char etc...
They can't accept references to values: they would generate a compile-time error if you assign them a null, as opposed to reference types, which can obviously accept it.
Why would you need that?
Because sometimes your value type variables could receive null references returned by something that didn't work very well, like a missing or undefined variable returned from a database.
I suggest you to read the Microsoft Documentation because it covers the subject quite well.
Means that the variable declared with (int?) is nullable
int i1=1; //ok
int i2=null; //not ok
int? i3=1; //ok
int? i4=null; //ok
To add on to the answers above, here is a code sample
struct Test
{
int something;
}
struct NullableTest
{
int something;
}
class Example
{
public void Demo()
{
Test t = new Test();
t = null;
NullableTest? t2 = new NullableTest();
t2 = null;
}
}
This would give a compilation error:
Error 12 Cannot convert null to 'Test' because it is a non-nullable
value type
Notice that there is no compilation error for NullableTest. (note the ? in the declaration of t2)
To add on to the other answers:
Starting in C# 8.0, Nullable<> and ? are NOT always interchangeable. Nullable<> only works with Value types, whereas ? works with both Reference and Value types.
These can be seen here in the documentation
"A nullable reference type is noted using the same syntax as nullable
value types: a ? is appended to the type of the variable."
And here
public struct Nullable<T> where T : struct
I was doing some testing with nullable types, and it didn't work quite as I expected:
int? testInt = 0;
Type nullableType = typeof(int?);
Assert.AreEqual(nullableType, testInt.GetType()); // not the same type
This doesn't work either:
DateTime? test = new DateTime(434523452345);
Assert.IsTrue(test.GetType() == typeof(Nullable)); //FAIL
DateTime? test = new DateTime(434523452345);
Assert.IsTrue(test.GetType() == typeof(Nullable<>)); //STILL FAIL
My question is why does testInt.GetType() return int, and typeof(int?) return the true nullable type?
According to the MSDN :
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.
When you box a nullable object, only the underlying type is boxed.
Again, from MSDN :
Boxing a non-null nullable value type
boxes the value type itself, not the
System.Nullable that wraps the value
type.
Further to Romain's correct answer, if you want to compare the "real" types (ie, without implicitly converting any nullable type to its underlying type) then you can create an extension method like so:
public static class MyExtensionMethods
{
public static Type GetRealType<T>(this T source)
{
return typeof(T);
}
}
And then try the following tests:
int? a = 0;
Console.WriteLine(a.GetRealType() == typeof(int?)); // True
Console.WriteLine(a.GetRealType() == typeof(int)); // False
int b = 0;
Console.WriteLine(b.GetRealType() == typeof(int)); // True
Console.WriteLine(b.GetRealType() == typeof(int?)); // False
DateTime? c = DateTime.Now;
Console.WriteLine(c.GetRealType() == typeof(DateTime?)); // True
Console.WriteLine(c.GetRealType() == typeof(DateTime)); // False
DateTime d = DateTime.Now;
Console.WriteLine(d.GetRealType() == typeof(DateTime)); // True
Console.WriteLine(d.GetRealType() == typeof(DateTime?)); // False
EDIT...
For completeness -- and prompted by SLaks's comments below -- here's an alternative version that only uses the compile-time type when source is either null or Nullable<>; otherwise it uses GetType and returns the runtime type:
public static class MyExtensionMethods
{
public static Type GetRealType<T>(this T source)
{
Type t = typeof(T);
if ((source == null) || (Nullable.GetUnderlyingType(t) != null))
return t;
return source.GetType();
}
}
Although C# pretends that value-type storage locations hold instances of types derived from System.ValueType, which in turn derives from System.Object, that isn't really true. Each type derived from System.ValueType actually represents two very different kinds of things:
A collection of bytes which (for primitive types) represents the data directly, or (for non-primitive structure types) holds the contents of all fields, public and private, but does not hold any type information.
A standalone heap object, which contains an object header in addition to the above, whose type is derived from `System.ValueType`.
Storage locations of a value type hold the first; heap objects of a value type hold the second.
For various reasons, Microsoft decided that Nullable<T> should only support the first usage. If one attempts to pass a storage location of type Nullable<T> to code which expects a reference to a heap object, the system will convert the item to a T if HasValue is true, or else simply pass a null reference if HasValue is false. While there are ways to create a heap object of type Nullable<T>, the normal methods of converting a value-type storage location to a heap object will never generate one.
Note also that calling GetType() on a value storage location won't actually evaluate the type of the storage location, but will instead convert the contents of that storage location to a heap object and then return the type of the resulting object. Because storage locations of type Nullable<T> get converted either to object instances of T or to null, nothing in an object instance will say whether the storage location from which it came was a Nullable<T>.
A simple way to check that is using the "is" operator:
(i is Nullable<int>) || (i is Nullable<long>) || (i is Nullable<float>) || (i is Nullable<short>)
I figured out ti reading these two MSDN pages:
http://msdn.microsoft.com/en-us/library/ms366789(v=vs.90).aspx
http://msdn.microsoft.com/en-us/library/ms228597%28v=VS.90%29.aspx
Cheers!