2010-01-08 12 views
13

Czy próbowałeś kiedyś użyć metody Convert.ChangeType(), aby przekonwertować wartość na typ Nullable<T>? Niezręcznie, wyrzuci on InvalidCastException mówiąc: "obiektu Null nie można przekonwertować na typ wartości".Dlaczego Nullable <T> jest uważany za typ wartości?

Spróbuj uruchomić to na natychmiastowe okna: ?System.Convert.ChangeType(null, typeof(int?))

Z jakiegoś niejasnego powodu Nullables są uważane typy wartości. Na przykład typeof(int?).IsValueType zwraca true.

Dla mnie, od akceptować null, jest to typ klasy, a nie typ wartości. Czy ktokolwiek wie, dlaczego byłby inaczej wdrażany?

Odpowiedz

27

System.Nullable<T> jest technicznie konstrukcja, więc jest to typ wartości (wartość null dla Nullable<T> nie jest dokładnie to samo, co null odniesienia. Jest to logiczna flaga oznaczająca brak wartości). Jednakże, jest to traktowane specjalnie przez środowisko wykonawcze, co czyni go niezręcznym typem wartości. Po pierwsze, nie spełnia warunku typu where T : struct (nie jest to również satysfakcjonujące: where T : class). Po drugie, wykazuje interesujące zachowanie bokserskie. Boks Nullable<T> spowoduje:

  • A null odniesienia, jeżeli wartość jest null.
  • Wartość pola podrzędnego typu, jeśli rzeczywiście zawiera wartość. Oznacza to, że w sprawozdaniu:

    int? x = 2; 
    object y = x; 
    

    y nie jest box Nullable<int>. Jest to po prostu pudełkowy int. Możesz rozpakować dowolną wartość w pudełku typu T na Nullable<T> (i T, oczywiście). Przesyłanie odwołania do wartości null na wartość Nullable<T> powoduje uzyskanie wartości (jak można się spodziewać).

To szczególne traktowanie przez środowisko sprawia typy dopuszczające wartość null pracować bardziej podobny do sposobu null pracuje w rodzaju odniesienia.

+3

Dziwne zachowanie boksu zabiera trochę czasu, ale cieszę się, że tak właśnie jest; w przeciwnym razie zostanie utracona znaczna część wartości 'Nullable ' (która pochodzi z przezroczystości przechodzącej przez wartość). – LBushkin

+1

W rzeczywistości zachowanie boksu było zmianą, która nastąpiła pod koniec cyklu programowania .NET 2.0. We wczesnych betach 'Nullable ' był prostą strukturą. W praktyce, gdy faktycznie używasz typów nulla do przechowywania nieistniejących wartości, ja też czuję, że to zachowanie jest bardziej naturalne. –

+0

Świetne dodane informacje przy okazji – Nick

11

Nullable<T> jest typ wartości (jest to struktura, zobacz w MSDN documentation), ale istnieje niejawna konwersja z null do Nullable<T> bez wartości (x.HasValue == false). Istnieje również niejawna konwersja wartości typu T na wartości typu Nullable<T>.

Dodatkowo wszystkie operatory są przenoszone z typowych typów, aby pracować bezpośrednio z typami zerowymi.

+0

Dlaczego upadły? Jestem w błędzie? Jeśli tak, proszę mnie oświecić. –

+0

Przegłosowałem anulowanie w dół. :) –

2

Nullable<T> jest zaimplementowana jako struktura, a struktury są typami wartości.

+1

Ale żadna struct nie może otrzymać wartości "null". Wierzę, że Nullables są wystarczająco różne od struktur, aby nie były uważane za struktury. – jpbochi

+2

'Nullable ' nie może otrzymać wartości 'null' albo ma niejawną konwersję zi na' null'. Możesz to zaimplementować na dowolnej niestandardowej strukturze 'struct', jeśli sobie tego życzysz. – Aaronaught

+4

@Aaronaught: możesz zrobić coś * podobnie * z niestandardową strukturą, ale wiele zachowań typów pustych nie może być naśladowanych przez kod. Wartości Nullable nie są tylko rozwiązaniem bibliotecznym. Otrzymują specjalne wsparcie od kompilatora (a także CLR, jak sądzę). –

1

Właśnie zobaczyłem to pytanie na liście "powiązanych pytań" pod numerem Why Nullable<T> is a struct? i uważam, że moja odpowiedź również tutaj obowiązuje. Cały punkt Nullable<T> ma zachowywać się jak typ wartości pod każdym względem, z wyjątkiem możliwości pobrania wartości pustej.

Wartość zerowa odniesienia zerowego można rozpatrywać na dwa sposoby.Jedną jest to, że niczego nie odwołuje, a inną - że nie ma żadnej znaczącej wartości. Te rzeczy to dwa różne sposoby mówienia o tym samym, ale mają różne zastosowania.

daje nam możliwość powiedzenia "to nie ma znaczącej wartości" i do tego stopnia może mieć tę samą semantykę, co odwołanie zerowe, ale nie jest jak odniesienie w jakikolwiek inny sposób. Gdy wartość pusta to nieważność, to czysto "nie ma żadnej znaczącej wartości" null - nie "nie odnosi się do niczego", a gdy nie jest zerowa, zawiera wartość, a nie odnosi się do niej.

(Aaronaught twierdzi, że oznacza to, że Nullable nie może w rzeczywistości zawierać wartości null, podczas gdy ja się nie zgadzam, ponieważ na poziomie, na którym on działa, może mieć semantyczną wartość zerową, jego punkt warty jest rozważenia, nawet gdy "null" a Nullable różni się od odniesienia - tak naprawdę nasz brak zgody jest kwestią tego, jakiego poziomu abstrakcji wybieramy).