Coś, co właśnie przyszło mi dzisiaj do głowy, sprawiło, że podrapałem się w głowę.Jak jest możliwe boksowanie/rozpakowywanie Nullable <T>?
Dowolną zmienną typu Nullable<T>
można przypisać do null
. Na przykład:
int? i = null;
Na początku nie mogłem zobaczyć, jak byłoby to możliwe bez jakiś sposób definiowania niejawna konwersja z object
do Nullable<T>
:
public static implicit operator Nullable<T>(object box);
Ale powyżej operator wyraźnie nie istnieje, jako jeśli tak, to następuje również muszą być zgodne z prawem, przynajmniej w czasie kompilacji (co nie jest):
int? i = new object();
wtedy zdałem sobie sprawę, że PE rhaps typ Nullable<T>
mógł zdefiniować niejawna konwersja do jakiegoś dowolnego typu referencyjnego, że nigdy nie może być instancja, tak:
public abstract class DummyBox
{
private DummyBox()
{ }
}
public struct Nullable<T> where T : struct
{
public static implicit operator Nullable<T>(DummyBox box)
{
if (box == null)
{
return new Nullable<T>();
}
// This should never be possible, as a DummyBox cannot be instantiated.
throw new InvalidCastException();
}
}
to jednak nie wyjaśnia, co przyszło mi do głowy dalej: jeżeli nieruchomość HasValue
jest false
dla każdego Nullable<T>
wartość, to wartość ta zostanie zapakowane jako null
:
int? i = new int?();
object x = i; // Now x is null.
Ponadto, jeśli HasValue
jest true
, następnie wartością zostaną zapakowane jako T
zamiast T?
:
int? i = 5;
object x = i; // Now x is a boxed int, NOT a boxed Nullable<int>.
Ale to zdaje się sugerować, że istnieje zwyczaj niejawna konwersja z Nullable<T>
do object
:
public static implicit operator object(Nullable<T> value);
To oczywiście nie jest przypadek jako object
jest klasą bazową dla wszystkich typów, a zdefiniowane przez użytkownika niejawne konwersje do/z typów bazowych są niedozwolone (tak jak powinny być).
Wydaje się, że należy object x = i;
pole i
jak każdy inny rodzaj wartości, tak że x.GetType()
dałoby taki sam efekt jak typeof(int?)
(zamiast rzut NullReferenceException
).
Więc wykopał się trochę, a na pewno wystarczy, okazuje się to zachowanie jest charakterystyczne dla rodzaju Nullable<T>
, specjalnie zdefiniowane zarówno w C# i specyfikacji VB.NET, i nie powtarzalny w dowolnym zdefiniowanym przez użytkownika struct
(C#) lub Structure
(VB.NET).
Oto dlaczego wciąż jestem zdezorientowany.
Ten szczególny rodzaj boksowania i rozpakowywania wydaje się niemożliwy do wykonania ręcznie. Działa tylko dlatego, że zarówno C#, jak i VB.NET zapewniają specjalne traktowanie typu Nullable<T>
.
nie jest to teoretycznie możliwe, że może istnieć inny język CLI oparte gdzie
Nullable<T>
nie dano tej specjalnego traktowania? A zatem czy typNullable<T>
nie będzie miał innego zachowania niż w różnych językach?W jaki sposób C# i VB.NET osiągnąć to zachowanie? Czy jest obsługiwany przez CLR? (To znaczy, nie CLR pozwalają typ jakoś „obejścia” sposób, w jaki jest ona pudełkową, choć C# i VB.NET sami zakazać go?)
Czy to w ogóle możliwe (w języku C# lub VB.NET), aby umieścić w pudełku
Nullable<T>
jakoobject
?
Jest to kompilator JIT, który implementuje zachowanie. Więcej tutaj: http://stackoverflow.com/questions/1583050/performance-surprise-with-as-and-nullable-types/3076525#3076525 –
Zdaję sobie sprawę, że spóźniłem się o 7 lat na imprezę. Chciałbym jednak zasugerować, aby każdy, kto jest ciekawy, jak ja, również przeczytał źródło referencji, aby uzyskać więcej informacji. https://referencesource.microsoft.com/#mscorlib/system/nullable.cs, ffebe438fd9cbf0e – Licht