Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is Nullable<T> different from a similar custom C# struct?

In Nullable micro-optimizations, part one, Eric mentions that Nullable<T> has a strange boxing behaviour that could not be achieved by a similar user-defined type.

What are the special features that the C# language grants to the predefined Nullable<T> type? Especially the ones that could not be made to work on a MyNullable type.

Of course, Nullable<T> has special syntactic sugar T?, but my question is more about semantics.

like image 930
Eldritch Conundrum Avatar asked Dec 07 '22 10:12

Eldritch Conundrum


2 Answers

What I was getting at is: there is no such thing as a boxed nullable. When you box an int, you get a reference to a boxed int. When you box an int?, you get either a null reference or a reference to a boxed int. You never get a boxed int?.

You can easily make your own Optional<T> struct, but you can't implement a struct that has that boxing behaviour. Nullable<T>'s special behaviour is baked into the runtime.

This fact leads to a number of oddities. For example:

  • C# 4: Dynamic and Nullable<>

  • C# Reflection: How to get the type of a Nullable<int>?

  • Cannot change type to nullable in generic method

And FYI there are other ways in which the Nullable<T> type is "magical". For instance, though it is a struct type, it does not satisfy the struct constraint. There's no way for you to make your own struct that has that property.

like image 87
Eric Lippert Avatar answered Mar 25 '23 03:03

Eric Lippert


I found these two in the C# specifications:

  • The is operator works on T? as it would have on T, and the as operator can convert to nullable types.
  • Predefined and user-defined operators that operate on non-nullable value types are lifted to the nullable forms of those types.

Now, here are the features that I think are not limited to Nullable<T>:

  • The value in a switch can be of a nullable type. I don't think this counts, because switch also accepts user-defined implicit conversions that could be defined on a MyNullable type.
  • Nullable IDisposable types are supported, with a null check being inserted before the generated calls to Dispose(). I don't think this counts, because I could define MyNullable as a class and then it would be the same.

Here is what I am not sure about:

  • The specs mentions boxing/unboxing and implicit/explicit conversions, but I do not understand whether the same results can be achieved with a MyNullable.
like image 30
Eldritch Conundrum Avatar answered Mar 25 '23 02:03

Eldritch Conundrum