ValueType to małe białe kłamstwo.
Wbudowane typy liczbowe (int, long, byte), char, enums i structs są typami wartości.
Oznacza to, że mają różne koncepcje tożsamości i równoważności z typami obiektów. Jeśli wykonam x = y
, a x i y są typami odniesienia, to X i Y wskazują teraz dokładnie ten sam obiekt. Jednakże jeśli wykonam x = y
, a x i y są typami wartości, to x i y są teraz dwoma całkowicie różnymi obiektami, które są identyczne. (Ma to również swoje odzwierciedlenie w ==
i Equals
, ale można to zmienić).
(Tutaj ludzie zostają odsunięci na boczny tor przez mówienie o stosie i kupie, jeśli jeszcze tego nie zrobili, tak naprawdę jest to szczegół implementacji i choć ważny, nie jest celem rozróżnienia między wartością a typami odniesienia).
Obecnie jest to wszystko dobre i dobre, ale jedną z cech typów referencyjnych jest to, że wszystkie one korzystają z dziedziczenia z System.Object. Wartość typu int tak naprawdę nie jest, i to też jest dobre, ponieważ na wiele sposobów jest o wiele lepiej niż cztery bajty pamięci obsługiwane przez urocze instrukcje CPU, które są tak dobre w tym działaniu. Mimo to czasami warto jest traktować int, tak jak odziedziczone po System.Object, a więc możesz.
Oczywiście oznacza to, że możesz robić rzeczy z int, które mają sens tylko w System.Object, więc kiedy to zrobisz, int jest "boxed" i może być ponownie "unboxed".
To świetnie, ale co zrobić, jeśli chcemy zrobić coś konkretnego dla typów wartości? Co więcej, jeśli projektanci CLR wykonali (w szczególności chcieli kodu GetHashCode dla typów wartości związanych z opisaną wyżej wartościową ekwiwalentnością, zamiast równoważności opartej na tożsamości, którą mają obiekty)?
W tym celu mamy ValueType. System traktuje wszystkie typy wartości jako dziedziczące z tej klasy, która z kolei dziedziczy po Object. Enum z kolei dziedziczy po typie wartości, a wszystkie typy wyliczeniowe dziedziczą z niego, umożliwiając wspólną funkcjonalność we wszystkich tabelach.
Tak więc, jeśli kiedykolwiek chcesz traktować superklasę wszystkich typów wartości, użyj ValueType, ale jeśli chcesz faktycznie utworzyć typ wartości, utwórz odpowiednio struct lub enum.
Wspólna wyjaśnienie Rodzaj systemu:
Struktura jest typ wartości, który wywodzi się niejawnie z System.ValueType, które z kolei wywodzi się z System.Object. Struktura jest bardzo przydatna do reprezentowania wartości, których wymagania dotyczące pamięci są małe, oraz do przekazywania wartości jako wartości pochodnych do metod, które mają silnie wpisane parametry. W bibliotece klas .NET Framework wszystkie prymitywne typy danych (Boolean, Byte, Char, DateTime, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32 i UInt64) są zdefiniowane jako struktury.
Struktury, podobnie jak klasy, definiują zarówno dane (pola struktury), jak i operacje, które można wykonać na tych danych (metody konstrukcji). Oznacza to, że można wywoływać metody na strukturach, w tym metody wirtualne zdefiniowane w klasach System.Object i System.ValueType i dowolne metody zdefiniowane w samym typie wartości. Innymi słowy, struktury mogą zawierać pola, właściwości i zdarzenia, a także metody statyczne i niestatyczne. Można tworzyć instancje struktur, przekazywać je jako parametry, przechowywać je jako zmienne lokalne lub przechowywać je w polu innego typu wartości lub typu odniesienia. Struktury mogą również implementować interfejsy.
Typy wartości również różnią się od klas pod wieloma względami. Po pierwsze, mimo że pośrednio dziedziczą po System.ValueType, nie mogą bezpośrednio dziedziczyć z żadnego typu. Podobnie, wszystkie typy wartości są zapieczętowane, co oznacza, że nie można z nich wyprowadzić innego rodzaju. Nie wymagają również konstruktorów.
Dla każdego typu wartości środowisko wykonawcze wspólnego języka dostarcza odpowiedni typ pola, który jest klasą o tym samym stanie i zachowaniu co typ wartości. Instancja typu wartości jest wyświetlana w ramkach, gdy jest przekazywana do metody, która akceptuje parametr typu System.Object.Jest on rozpakowywany (to jest przekształcany z instancji klasy z powrotem do instancji typu wartości), gdy formant zwraca z wywołania metody, która akceptuje typ wartości jako parametr odsyłacza. Niektóre języki wymagają użycia specjalnej składni, gdy wymagany jest rodzaj pola; inne automatycznie używają typu pudełkowego, gdy jest to potrzebne. Podczas definiowania typu wartości definiuje się zarówno typ pudełkowy, jak i nieprzypisany.
Dziwnością ValueType jest umożliwienie powyższego.
Aby naprawdę dobrze zrozumieć, jak najlepiej tworzyć typy wartości, sprawdź Efektywne C# (2 wydanie), Bill Wagner; zwłaszcza pozycja 20. Zawiera również wiele innych bardzo przydatnych informacji. –
Dupe: [dlaczego-cant-i-wywodzić-z-systemu-enum-abstrakcyjna-klasa] (http://stackoverflow.com/questions/2324667/why-cant-i-derive- from-system-enum-abstract -class) – nawfal
Bardzo ładne i jasne pytanie. Oszczędza czas czytania. Zachęcam wszystkich do jasnego pisania tego pytania. Dzięki. –