2010-08-17 14 views
25

Próbowałem utworzyć ValueType.System.ValueType Rozumienie

Rozumiem, że stworzenie struktury pomogłoby mi.

Próbowałem również wyprowadzić typ z System.ValueType, który jest klasą abstrakcyjną.

ale mam komunikat o błędzie kompilatora „.. nie może pochodzić z klasy specjalnej System.ValueType

Kiedy widzę metadane ValueType, to wydaje się być zwykłym klasa abstrakcyjna.

  1. Co sprawiło, że było wyjątkowe?

  2. Czy jest to kompilator C#, który wyczuwa go jako wyjątkowy?

  3. Jeśli tak, czy zalecana jest z reguły konstrukcja kompilatora? Chodzi mi o to, czy jest to część specyfikacji języka wspólnego?

+1

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. –

+0

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

+1

Bardzo ładne i jasne pytanie. Oszczędza czas czytania. Zachęcam wszystkich do jasnego pisania tego pytania. Dzięki. –

Odpowiedz

26

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.

+1

Doceniam twoje wyjaśnienie. Ale w rzeczywistości, jak to się stało, że są wyjątkowe, to wciąż moje pytanie. System.ValueType nie jest zaplombowany i abstrakcyjny. Powinien więc kwalifikować się do bycia klasą rodzicielską.(Tak było w przypadku Enum, Int32 itd.) Jeśli kompilator C# traktuje go jako specjalny, powinien być również w innych językach (VB.Net, J #). Ale nie widzę notatki we wspólnej specyfikacji języka Microsoft. http://msdn.microsoft.com/en-us/library/12a7a7h3.aspx. Wciąż myślę, że coś jest ukryte, a to ma inne wytłumaczenie. – SaravananArumugam

+0

@ Karawandy Dodano wyjaśnienie powyżej w dokumentacji wspólnego systemu typu. Nie oznacza to, że typy wartości * pośrednio * pochodzą z System.ValueType, a jednocześnie podkreślają, że nie mogą one pochodzić z niczego. Rozwiązania skurczu dokonuje się przez dziwność, którą opisujesz. –

+2

Wygląda jak kaczka, szarlatany jak kaczka, pływa jak kaczka, to kaczka. Ale tak nie jest. –

1

nie można bezpośrednio podklasy ValueType. Wszystkie typy wartości pochodzą niejawnie z ValueType. W przeciwieństwie do typów referencyjnych, nie można wyprowadzić nowego typu z typu wartości. Jednak, podobnie jak typy referencyjne, struktury mogą implementować interfejsy.

zobaczyć MSDN wiedzieć więcej

+0

Każda niezasłonięta klasa powinna zostać uzyskana. Ale System.ValueType nie jest klasą zapieczętowaną. I mówi się, że jest to specjalna klasa. Co sprawia, że ​​jest wyjątkowy? jest moje pytanie – SaravananArumugam

+1

@ Saravanandss CLR .NET dawka to specjalne. – Arseny

3

Struktury są typy wartości. Typy wartości są specjalne, ponieważ są przydzielane na stosie zamiast na stercie. Aby "dziedziczyć" z ValueType, musisz utworzyć strukturę.

+0

Struktura to typ wartości to teoria. Ale moje pytanie było inne, Co sprawia, że ​​System.ValueType jest wyjątkowy? To nie jest zamknięta klasa, ale nie pozwala na wyprowadzenie. – SaravananArumugam

+1

@Saravanandss, "struktura jest typem wartości" to fakt, a nie teoria. To naprawdę się zdarza. –

1

C# nie pozwala typom wartości dziedziczyć z innych klas. Typy wartości (struct) mogą implementować interfejsy.

0
  1. "Klasa" rozszerza "System.Object", a "struct" rozszerza "System.ValueType". Jeśli mógłbyś rozszerzyć klasę "System.ValueType", nie byłoby większego sensu słowo kluczowe "struct".

  2. Tak

  3. Tak. Powinien istnieć tylko jeden sposób na osiągnięcie danej rzeczy. Gdy tylko otrzymasz dwie metody robienia czegoś, po prostu wszystko staje się bardziej skomplikowane. Główna zasada.

+0

Należy pamiętać, że wszystko w .NET jest ostatecznie System.Object. – Michael

+0

Nie zgadzam się z tym. W świecie programowania jest wiele sposobów na robienie rzeczy. Na przykład, jeśli (a == b) c = 0; jeszcze c = 1; jest równoważne c = (a == b)? 0: 1; I Nullable s = null; Int32? s = null; są równe. Nie ma reguły, która mówi, że powinien istnieć tylko jeden sposób na osiągnięcie czegoś. – SaravananArumugam

+0

Zawsze powinno być tak wiele sposobów, jak to możliwe, aby coś zrobić. Zawsze powinno być tak mało sposobów, jak to tylko możliwe, aby wszystko zostało zrobione. Obaj z tych darmowych programistów. –

2

Brak możliwości wyprowadzania z ValueType jest charakterystyczny dla kompilatora C#. Jeśli spojrzymy na zarządzanego kodu C++:

value class Foo {}; 
value class Foo : System::ValueType {}; 

Oba kompilacji i są identyczne. Oczywiście,

ref class Foo : System::ValueType {}; 

Wystąpi błąd C3050: klasa ref nie może dziedziczyć po "System :: ValueType".
Nie jesteś pewien, na co pozwalają inne kompilatory.

Jeśli chcesz czerpać z ValueType w języku C#, użyj struct, a nie klasy, a kompilator się tym zajmie.

0

To mnie wprawia w zakłopotanie ... Enum wywodzi się z ValueType. Co sprawia, że ​​myślę, że powyższe jest tylko ograniczeniem kompilatora.

[Serializable, ComVisible(true)] 
public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible 
{ 
    ... 
} 
+1

W niektórych kontekstach środowisko wykonawcze będzie traktować typy w różny sposób w zależności od tego, czy pochodzą one z 'ValueType'. Jeśli kompilator zezwolił na stworzenie klasy, która pochodziła od 'ValueType' i nie zawierała żadnego kodu, taka klasa zachowałaby się jak struktura. Jeśli klasa zawiera kod, taki kod prawdopodobnie nie zadziałałby, ponieważ klasy i klasy inaczej uzyskują dostęp do tego '' '; jeśli kompilator nie wiedział, że "ten" był strukturą, wygenerowałby zły kod, aby uzyskać do niego dostęp. – supercat

Powiązane problemy