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

不打扰是莪最后的温柔 提交于 2019-12-04 09:54:07
Eric Lippert

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:

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.

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.

C# lifts operators on nullable types. For example:

int? SumNullableInts(int? a, int? b)
{
    return a + b;
}

You would have to do a lot of reflection work in MyNullable<T> to support that, and then the following would compile, where it shouldn't:

MyNullable<List<string>.Enumerator> SumNullableEnumerators(MyNullable<List<string>.Enumerator> a, MyNullable<List<string>.Enumerator> b)
{
    return a + b;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!