问题
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.
回答1:
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.
回答2:
I found these two in the C# specifications:
- The
is
operator works onT?
as it would have onT
, and theas
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.
回答3:
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;
}
来源:https://stackoverflow.com/questions/13980303/how-is-nullablet-different-from-a-similar-custom-c-sharp-struct