Nullable restrictions [duplicate] - c#

This question already has answers here:
Why can't I write Nullable<Nullable<int>>?
(5 answers)
Closed 5 years ago.
Does anyone know why this code doesn't compile?
Nullable<Nullable<int>> n = null;
I realize Nullable has a constraint
where T : struct
But Nullable is struct. I also know this constraint has a restriction "The type argument must be a value type. Any value type except Nullable can be specified." (https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters).
So how does it work? Is this solved on compiler level?

The error message is:
The type int? must be a non-nullable value type in order to use it
as parameter 'T' in the generic type or method Nullable<T>
So it must not only be a value type but a non-nullable value type. But Nullable<int> is a nullable value type.
Here's the compiler error CS0453 which also shows this example:
This error occurs when you use a non-value type argument in
instantiating a generic type or method which has the value constraint
on it. It can also occur when you use a nullable value type argument.
Q: Is this solved on compiler level?
Yes, which means it' not very interesting to know how they achieved this constraint. It's an implementation detail of the compiler which doesn't need to use a C# language feature.
Why is not allowed?
Well, what would be the benefit of a Nullable<Nulable<int>>? Nullables were introduced to give value types the opportunity to be null(so undefined, without value). This is already achieved for a Nullable<int>, it can be null. So by nesting it in another nullable you would not get anything. It's not allowed for the same reason why you can't have a Nullable<string>, a string as every other reference type can already be null.

Related

How to specify that a generic method returns a non-nullable reference type? [duplicate]

This question already has answers here:
Why does Visual Studio Type a Newly Minted Array as Nullable?
(3 answers)
Closed 2 years ago.
If I have the C# 8 code:
class Foo {}
And later:
#nullable enable
var bar = new Foo();
Then the type of bar is Foo?. This seems clearly incorrect, as a new expression can't return null. Why would bar be a nullable reference? I even looked up the Nullable Reference Type Specification, and found the following:
Expressions that are never null
The null state of the following expression forms is always "not null":
...
new expressions (object, delegate, anonymous object and array creation expressions)
...
And also:
Type inference for var
The type inferred for local variables declared with var is informed by the null state of the initializing expression.
var x = E;
If the type of E is a nullable reference type C? and the null state of E is "not null" then the type inferred for x is C. Otherwise, the inferred type is the type of E.
The nullability of the type inferred for x is determined as described above, based on the annotation context of the var, just as if the type had been given explicitly in that position.
So based on everything I can find in the spec, bar in my very simple example should be of type Foo, not type Foo?. What am I missing?
If var were to infer its nullability from the expression, then in many instances you would not be able to assign a null to it later on. For example, var s = "";.
There was a discussion to allow var? to express "the nullable version of the type", but it had several issues. Would the regular var be restricted to infer a non-nullable type?
If yes, then (1) we're creating adoption pain as users need to add more ? annotations, (2) we have an inconsistent nullability with var pattern which had already shipped, (3) there are some questions with nullable value types (int?).
If no, then the intent of the code would not be very clear. var? would clearly indicate a nullable type, but var would be a mixed bag of nullable and non-nullable.
The decision to infer a nullable type for var was recorded in the LDM notes from 2019-12-18.

How can I initialize a System.Nullable<Int32>? [duplicate]

This question already has answers here:
GetType on Nullable Boolean
(2 answers)
Closed 1 year ago.
I need a Nullable type but how do I initialize such a variable? Whenever I try to do this it automatically converts to a normal Int32.
Nullable<Int32> nullableInt32 = new Nullable<Int32>(3);
Console.WriteLine(nullableInt32.GetType()); // gives me System.Int32
Is this a bug? How can I actually initalize the Nullable?
From Microsoft's documentation:
If you want to determine whether an instance is of a nullable value type, don't use the Object.GetType method to get a Type instance to be tested with the preceding code. When you call the Object.GetType method on an instance of a nullable value type, the instance is boxed to Object. As boxing of a non-null instance of a nullable value type is equivalent to boxing of a value of the underlying type, GetType returns a Type instance that represents the underlying type of a nullable value type.
So your int? gets boxed to int, and GetType() is called on the boxed instance.
Unless you know the type at compile time and use typeof, there is no way to get a type of a nullable object:
var type = typeof(int?);
In practice this shouldn't matter because if you don't know the type at compile time, it means you're using some sort of type erasure (i.e. a cast to object), and that means boxing, and nullable value types don't exist there. You can't use polymorphism because that doesn't work with value types.
If you think you have a valid need for this, feel free to explain your use case in the comments.

Nullable<int?> is not possible, Why not? [duplicate]

This question already has answers here:
Why can't I write Nullable<Nullable<int>>?
(5 answers)
Closed 8 years ago.
Excuse me if its a silly question, I am trying to get a better understanding of Nullable types in .Net.
From what i notice from Microsoft source code (using ReSharper), I understand that Nullable is a struct and T needs to be a struct
public struct Nullable<T> where T : struct
Now, I tried to do something like this
public struct CustomNullable<T> where T : struct
{
}
public class CustomNullableClass<T> where T : struct
{
}
And I get an error when I compile:
Nullable<int?> a = null;
Nullable<Nullable<int>> a1 = null;
For the above mentioned code I get an error 'Only non-nullable value types could be underlying of System.Nullable', but how is this enforced in the Nullable type ?
And for
CustomNullable<int?> a2 = null;
CustomNullableClass<int?> a3 = null;
I get an error 'The type System.Nullable must be non-nullable value type in order to use it as parameter T '.
I am bit confused now, can some one help me understand whats going on or have I not understood something ?
Thanks a lot in advance.
EDIT:
If structs are value types and value types can't be null, how can a Nullable be a struct?
Credit : spender
Actually, it's an internal hack somewhere in the C# compiler (guessing). You cannot replicate it in your own classes. If you make your own type, using the exact same IL, it will not enforce that additional hidden constraint.
There is special compiler support specifically for Nullable. You're not capable of reproducing a number of different possible behaviors of Nullable with a custom struct. One of those behaviors is the one that you've mentioned here, that Nullable doesn't meet the generic constraint for a struct despite being a struct.

Why string or object type don't support nullable reference type? [duplicate]

This question already has answers here:
C# nullable string error
(5 answers)
Closed 8 years ago.
Look into following code block:
//Declaring nullable variables.
//Valid for int, char, long...
Nullable<int> _intVar;
Nullable<char> _charVar;
//trying to declare nullable string/object variables
//gives compile time error.
Nullable<string> _stringVar;
Nullable<object> _objVar;
While compiling code compiler gives following error message:
The type 'string'/'object' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable'
I read it several times but still unable to understand. Can anyone clarify this? Why object or string dont support nullable reference type?
object and string are reference types, so they're already nullable. For example, this is already valid:
string x = null;
The Nullable<T> generic type is only for cases where T is a non-nullable value type.
In the declaration for Nullable<T> there is a constraint on T:
public struct Nullable<T> where T : struct
That where T : struct is precisely the part that constrains T to be a non-nullable value type.
Nullable<T> is defined as:
public struct Nullable<T> where T : struct
meaning: it only works on value-type T (excluding Nullable<TSomethingElse> itself).
You cannot use Nullable<T> on reference-types (or on Nullable<T>), but you don't need to since all reference-types (including object and string) are already "nullable", in that you can assign null to them.
string and object are reference types, and therefore are "nullable" already. The Nullable<T> type exists as a wrapper around value types that don't support null out of the box.
string myString = null //fine
int myInt = null //compiler error

Are nullable value types just wrappers around the regular value type?

The reason I ask is that you can cast a nullable type to a regular type with the Value property. That makes me think that the regular type is just wrapped up in the nullable type.
Yes, it is a generic struct:
public struct Nullable<T> where T : struct, new()
This is probably more confusing if you've only seen the T? syntax - but that is just syntactic sugar, the compiler is changing it to Nullable<T>.
Source: http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx , http://msdn.microsoft.com/en-us/library/1t3y8s4s.aspx
Yes - 'Nullable<T> Structure':
Represents an object whose underlying
type is a value type that can also be
assigned null like a reference type.
[BTW, if your curious you can use Reflector to 'look under the hood']
According to MSDN "Nullable types are instances of the System.Nullable<T> struct. A nullable type can represent the correct range of values for its underlying value type, plus an additional null value"

Categories