Rozdział 2...
Serwis znalezionych hasełOdnośniki
- Smutek to uczucie, jak gdyby się tonęło, jak gdyby grzebano cię w ziemi.
- Ogniem i mieczem - Tom I Rozdzial VI- Moci ksi - odpar Bychowiec - aska to wysoka waszej ksicej moci, e mogc rozkaza, na moj wol to zdajesz, ktrej aski nie...
- Przedstawiony w tym rozdziale projekt pomylany by jako opisowa analiza wywiadw przeprowadzanych przez kuratorw z podopiecznymi, oparta na badaniu aktw mowy...
- ROZDZIAŁ 38ODSIECZPomimo związanych na plecach nadgarstków, Perrin usiłował znaleźć wygodniejszą pozycję, aż wreszcie westchnął i poddał się...
- Jak wspomniano w poprzednim rozdziale, tworzenie aplikacji modularnej wymaga dodatkowych prac projektowych i podjęcia odpowiednich decyzji, ale w...
- ¨W każdym rozdziale poznajesz nowe sposoby lepszego rozumienia i pobudzania swoich manifestacyjnych sił...
- Rozdział 30 - Nigdy nie widziałeś czegoś takiego na własne oczy?Sam podskoczył z wrażenia...
- Rozdział 96Susan siedziała na sofie w Węźle nr 3, cała mokra i drżąca...
- Rozdział 7 Ażeby być sprawiedliwym, musze opowiedzieć także i o dobrych uczynkach Horemheba...
- Rozdział 11 ZAKOŃCZENIE Żyjemy w zadziwiającym świecie...
- Rozdzia 50Mary zmara o poranku...
Smutek to uczucie, jak gdyby się tonęło, jak gdyby grzebano cię w ziemi.
n Wspólny system typów
81
FooDerived d = new FooDerived();
FooBase b = d;
IFoo i = d;
b.Foo(); // Wyświetla "FooBase::Foo"
b.Bar(); // Wyświetla "FooBase::Bar"
d.Foo(); // Wyświetla "FooDerived::Foo"
d.Bar(); // Wyświetla "FooDerived::Bar"
i.Foo(); // Wyświetla "FooDerived::Foo"
Wybór między klasą abstrakcyjną a interfejsem
Klasy abstrakcyjne i interfejsy pełnią podobne funkcje, ale mają różne wady i zalety. Klasy abstrakcyjne mogą oferować nie tylko interfejs, lecz również implementację, co znacznie upraszcza kontrolę wersji. Należy z nich więc korzystać w większości sytuacji, choć w niektórych przypadkach użycie interfejsów również będzie miało sens.
Jako przykład problemów z kontrolą wersji rozważmy następującą sytuację: opublikowaliśmy klasę abstrakcyjną i interfejs z dwiema metodami, void A() i void B(). Zasadniczo jesteśmy na nie skazani, tzn. nie możemy się ich pozbyć, nie naruszając typów, które wywodzą się z naszej klasy albo implementują nasz interfejs. Klasy abstrakcyjne można jednak z czasem rozszerzać. Gdybyśmy chcieli na przykład dodać nową metodę void C(), moglibyśmy zdefiniować ją w klasie abstrakcyjnej z pewną domyślną implementacją. W podobny sposób moglibyśmy dodać pomocnicze, przeciążone wersje metody. W przypadku interfejsów jest to po prostu niemożliwe.
Z drugiej strony klasy abstrakcyjne przejmują hierarchię typów klas pochodnych. Klasa może implementować interfejs, a mimo to nadal zachować jakąś sensowną hierarchię typów. W przypadku klas abstrakcyjnych jest inaczej. Co więcej, interfejsy pozwalają stosować dziedziczenie wielokrotne, a klasy abstrakcyjne — nie.
Pieczętowanie typów i metod
Typ może być oznaczony jako zapieczętowany, co znaczy, że nie można wywodzić z niego dalszych typów. W C# sygnalizuje się to za pomocą słowa kluczowego sealed: sealed class Foo {}
Nie można utworzyć podklasy typu Foo. Wszystkie niestandardowe typy wartościowe są niejawnie zapieczętowane wskutek zasady, że nie można dziedziczyć po typach wartościowych zdefiniowanych przez użytkownika.
Zauważmy też, że typ zarówno zapieczętowany, jak i abstrakcyjny z definicji nie może mieć konkretnej instancji. Uważa się go zatem za typ statyczny, czyli taki, który powinien mieć wyłącznie składowe statyczne. Słowo kluczowe języka C# dla klas statycznych używa właśnie takiego wzorca w IL, tzn. poniższe dwa wiersze kodu są semantycznie równoważne: static class Foo { /* … */ }
abstract sealed class Foo { /* …*/ }
82
Część I n Podstawowe informacje o CLR
Kompilator C# zapobiega przypadkowemu dodaniu składowych instancyjnych do klasy statycznej, tym samym unikając tworzenia całkowicie niedostępnych składowych.
Poszczególne metody wirtualne również mogą być zapieczętowane, co wskazuje, że ich dalsze przesłanianie jest nielegalne. Dalsze typy pochodne mogą jednak nadal ukryć metodę przez tworzenie nowych slotów, na przykład:
class Base
{ protected virtual void Bar() { /* … */ }
}
class Derived : Base
{ protected override sealed void Bar() { /* … */ }
}
W języku C# do pieczętowania metod używa się słowa kluczowego sealed. W powyższym przykładzie oznacza to, że podklasy Base nie mogą przesłaniać metody Bar.
Sprawdzanie typów podczas wykonywania programu
CLR oferuje różne sposoby przeprowadzania dynamicznej kontroli typów w celu zweryfi-kowania polimorficznej zgodności między instancją a typem. Dysponując obiektem o i typem T, możemy użyć instrukcji IL castclass oraz isinst, aby sprawdzić, czy o jest typu T
albo czy jego typ implementuje T (jeśli T jest interfejsem) lub jest podtypem T, co oznacza, że można bezpiecznie traktować go jak T. W języku C# instrukcje te są eksponowane jako rzutowanie oraz słowa kluczowe is i as:
object o = /* … */;
string s1 = (string)o; // Rzutowanie używa instrukcji castclass
string s2 = o as string; // Słowo kluczowe as używa instrukcji isinst
if (o is string) { // Słowo kluczowe is używa instrukcji isinst
// …
}
W tym przykładzie rzutowanie używa instrukcji castclass, aby dynamicznie sprawdzić, czy instancja o jest typu System.String. Jeśli nie jest, środowisko uruchomieniowe zgłasza wyjątek CastClassExceStion. Słowa kluczowe as i is używają instrukcji isinst. Instrukcja ta bardzo przypomina castclass, ale nie generuje wyjątku; jeśli typ nie przejdzie pomyślnie testu, instrukcja zwraca 0. W przypadku słowa kluczowego as oznacza to, że jeśli instancja nie jest prawidłowego typu, wynik będzie równy null; w przypadku słowa kluczowego is ten sam warunek daje wynik false.
Przestrzenie nazw: organizowanie typów
Wszystkie dobre środowiska programistyczne mają system tworzenia modułów i pakietów.
Pominąwszy podzespoły i moduły, które stanowią fizyczne jednostki dystrybucji i wielokrotnego użytku — podzespoły zostaną opisane szczegółowo w rozdziale 4. — mechanizmem pakowania logicznego są przestrzenie nazw. Nazwę typu połączoną z jego przestrzenią
Rozdział 2. n Wspólny system typów
83
nazw określa się mianem nazwy w pełni kwalifikowanej. Wszystkie typy składające się na
.NET Framework mają przestrzenie nazw, zwykle zaczynające się od System, choć niektóre typy specyficzne dla produktu zaczynają się od Microsoft. W CTS pojęcie przestrzeni nazw nie występuje. Wszystkie typy i referencje do nich są emitowane z wykorzystaniem w pełni kwalifikowanych nazw.
Przestrzenie nazw mają naturę hierarchiczną. Odwołujemy się do nich według kolejności, zatem na przykład korzeń hierarchii jest poziomem pierwszym, położony pod nim zbiór nazw
— drugim itd. Rozważmy na przykład w pełni kwalifikowaną nazwę System.Collections.