Platforma .NET
-
- Maciej Zdanowicz,
- 01.10.2004
Platforma .NET powstawała w wyniku ewolucji modelu komponentowego COM, ale gdy ujrzała światło dzienne, okazała się prawdziwą rewolucją w programowaniu. Biorąc jednak pod uwagę, jak .NET porządkuje i ułatwia pracę programisty, można stwierdzić, że już najwyższy czas na taką rewolucję.
Platforma .NET powstawała w wyniku ewolucji modelu komponentowego COM, ale gdy ujrzała światło dzienne, okazała się prawdziwą rewolucją w programowaniu. Biorąc jednak pod uwagę, jak .NET porządkuje i ułatwia pracę programisty, można stwierdzić, że już najwyższy czas na taką rewolucję.
Platforma .NET jest elementem większej układanki - nowego ładu, w którym wszystkie komputery są równe i mogą sobie nawzajem świadczyć usługi bez względu na to, gdzie fizycznie się znajdują oraz jaki system operacyjny nimi steruje. Komputery te wspólnie tworzą platformę, na której uruchamiane są rozproszone aplikacje, które aby wykonać swoje zadania, korzystają z wielu usług udostępnionych przez różnych dostawców. Na takiej platformie raz napisany kod - opublikowany w postaci usługi lub komponentu - wzbogaca samą platformę i jest do wykorzystania przez wszystkich zainteresowanych, bez względu na język programowania czy architekturę sprzętową.
Mimo że przytoczona wizja jednej zintegrowanej wirtualnej rzeczywistości jest wciąż dość odległa, to za sprawą platformy .NET wiele jej elementów dostępnych jest dla programistów już dzisiaj. Obecność w systemie operacyjnym rozszerzenia Microsoft .NET Framework (które powoli staje się jednym z podstawowych składników systemu), umożliwia programistom zastosowanie najnowszych technologii programistycznych, a w konsekwencji uporządkowanie swojego warsztatu i korzystanie z ułatwień oraz wygody, jaką oferuje platforma .NET.
Programowanie platformy .NET różni się od klasycznego programowania platformy Win32 na bardzo wielu płaszczyznach. Kod wynikowy, który otrzymujemy po kompilacji programu, nie jest kodem maszynowym przeznaczonym do konkretnego procesora, lecz specjalnym kodem pośrednim CIL (Common Intermediate Language), niezależnym od platformy sprzętowej. W dodatku CIL jest kodem znacznie wyższego poziomu niż np. kod maszynowy x86 i zamiast operować jedynie na rejestrach i adresach pamięci, posługuje się takimi pojęciami, jak klasa, metoda, tablica czy wyjątek. Można powiedzieć, że jest w pewnym sensie językiem obiektowym.

Różne wersje Microsoft .NET Framework mogą być zainstalowane równolegle. Z jakiej wersji korzysta dana aplikacja, określają wpisy w jej pliku konfiguracyjnym.
Wprowadzenie pomiędzy kod źródłowy i kod maszynowy dodatkowej pośredniej postaci kodu ma na celu nie tylko uzyskanie niezależności od platformy. Drugim ważnym powodem jest zwiększenie bezpieczeństwa aplikacji przez nadzorowanie kodu. Zanim CLR przetłumaczy kod pośredni na maszynowy, może sprawdzić, czy program nie wykonuje niedozwolonych operacji lub czy kod został dopuszczony do wykonania za pomocą zasad systemowych. CIL nazywany jest też kodem zarządzanym, co jeszcze precyzyjniej oddaje naturę działań CLR w zakresie gospodarowania pamięcią. Aplikacje. NET z reguły same nie zwalniają pamięci, lecz zajmuje się tym tzw. garbage collector, który śledzi obiekty w pamięci i w razie potrzeby zwalnia już niepotrzebne. Tego rodzaju mechanizmy wbudowane w platformę. NET nie tylko ułatwiają pracę programistom i zapobiegają powstawaniu błędów, ale pozwalają też tworzyć bardziej stabilne i niezawodne aplikacje.

Microsoft .NET Framework SDK zawiera dokumentację platformy .NET, materiały dydaktyczne, kompilatory, przykładowe programy oraz narzędzia dodatkowe, umożliwiające budowę aplikacji .NET.
W niektórych przypadkach aplikacje .NET mogą nawet działać szybciej niż klasyczne aplikacje niezarządzane, bo ostateczna kompilacja kodu odbywa się dopiero w docelowym systemie, w którym aplikacja ma zostać uruchomiona, a więc znany jest np. typ lub liczba dostępnych procesorów. Podczas kompilacji CLR może wykorzystać te informacje do zoptymalizowania kodu - usuwając instrukcje, których wykonanie uwarunkowane jest dostępnością (brakujących w tym wypadku) zasobów sprzętowych, lub wprowadzając instrukcje zastępcze, wykorzystujące zaawansowane możliwości nowszego procesora. Aplikacje napisane na platformę .NET zapisywane są, podobnie jak zwykłe aplikacje, w plikach EXE lub jak biblioteki - w plikach DLL. W obu wypadkach podobieństwo do zwykłych programów i bibliotek widoczne jest tylko z zewnątrz. Na platformie .NET operuje się pojęciem podzespołu (assembly). Podzespoły są najmniejszymi samodzielnymi komponentami, które mogą być wielokrotnie wykorzystywane, rozróżniane za pomocą numeru wersji oraz dla których można określić zasady bezpieczeństwa. Wewnątrz podzespołu może się znajdować jeden lub więcej plików-modułów z kodem programu lub plików z zasobami wykorzystywanymi przez aplikację lub bibliotekę.

Narzędzia administracyjne platformy .NET pozwalają określić precyzyjne zasady bezpieczeństwa stosowane do poszczególnych komponentów.
Z obecności metadanych w pliku modułu wynika wiele pozytywnych konsekwencji. Jedną z nich, szczególnie istotną dla programistów, jest znaczne ułatwienie używania gotowych komponentów. Skorzystanie z komponentu nie wymaga już importowania odpowiedniej biblioteki typów - wszystkie informacje są zawarte w samym komponencie. Poza tym aplikacja platformy .NET może za pomocą mechanizmu Reflection poznać swoją obiektową strukturę. Wreszcie możliwe jest precyzyjne określenie wymaganych przez komponent podzespołów zewnętrznych. Metadane są też wykorzystywane przez CLR podczas uruchamiania kodu, m.in. w celu sprawdzenia, czy wykonywane operacje są bezpieczne, a typy danych - zgodne.
Platforma .NET rozwiązuje również problem współpracy komponentów napisanych w różnych językach programowania i działających na różnych platformach sprzętowych i systemowych, zwłaszcza że nie jest z nią związany jeden konkretny język. Owszem, głównym językiem, zaprojektowanym specjalnie pod kątem platformy .NET, jest C#, ale równie dobrze aplikacje można pisać w językach Visual Basic .NET, Delphi .NET, C++ .NET, J# .NET oraz w co najmniej dwudziestu innych. Co więcej, poszczególne elementy aplikacji można napisać w różnych językach, a wszystkie zostaną skompilowane do postaci tego samego kodu pośredniego CIL. Taka współpraca jest możliwa między innymi dlatego, że wszystkie języki zgodne z platformą .NET stosują ujednolicony system typów, co gwarantuje, że np. podstawowy typ całkowity będzie zawsze reprezentowany za pomocą 32 bitów.
Obok CLR bardzo ważnym elementem platformy .NET jest obiektowa biblioteka FCL ( .NET Framework Class Library) , która zawiera gotowe komponenty do budowy graficznych aplikacji Windows, aplikacji do serwera internetowego za pomocą Web Forms, aplikacji konsolowych, usług systemowych, usług sieciowych (Web Services) i własnych bibliotek komponentów. Biblioteka FCL jest jednocześnie bezpiecznym interfejsem do funkcji Windows API. Aplikacje dotnetowe mogą z nich korzystać za pośrednictwem uporządkowanej hierarchicznej struktury klas oraz za pomocą przestrzeni nazw, które grupują obiekty powiązane funkcjonalnie.
Nowy model programowania na platformie .NET dobrze się sprawdzi przy budowie większości nowych aplikacji, ale trzeba pamiętać, że są i takie zastosowania, z którymi .NET Framework sobie nie poradzi. Po pierwsze, dlatego, że platforma .NET nie oferuje jeszcze odpowiedników wszystkich funkcji systemu Windows, a po drugie, wiele aplikacji - które są stale rozwijane - zostało już napisanych za pomocą klasycznych narzędzi i pisanie ich od początku na nowej platformie jest nieopłacalne. Aby rozwiązać te wszystkie problemy, w platformę .NET wbudowano mechanizmy, które umożliwiają współpracę kodu zarządzanego i niezarządzanego nawet w obrębie jednej aplikacji.
Po pierwsze, aplikacje .NET mogą wywoływać funkcje z klasycznych bibliotek DLL za pomocą mechanizmu P/Invoke (Platform Invoke). Na podobnej zasadzie działa sama platforma .NET, ponieważ wiele metod udostępnianych przez klasy zawarte w FCL wykonuje wewnętrzne odwołania do klasycznych funkcji API - przykładowe żądanie utworzenia nowego pliku przecież i tak musi się skończyć wywołaniem wewnętrznej funkcji systemu operacyjnego, która współpracując ze sterownikiem twardego dysku spowoduje zapisanie na dysku odpowiednich sektorów. Chodzi jednak o to, aby takich bezpośrednich wywołań nie nadużywać, zwłaszcza gdy platforma oferuje odpowiednie funkcje zastępcze. Korzystając z P/Invoke, trzeba pamiętać, że rezygnuje się z wielu mechanizmów bezpieczeństwa aplikacji zapewnianych przez platformę .NET. Aplikacje korzystające z kodu niezarządzanego, a w szczególności z funkcji systemu operacyjnego automatycznie stają się też zależne od platformy systemowej i sprzętowej.
Oprócz P/Invoke są jeszcze dwa scenariusze współpracy kodu zarządzanego i niezarządzanego - oba oparte na technologii COM. Pierwszy to wykorzystywanie na platformie .NET klasycznych komponentów COM, a drugi - udostępnianie za pomocą COM komponentów .NET klasycznym aplikacjom. W obu przypadkach tworzona jest specjalna warstwa pośrednia, opakowująca udostępniany komponent. Mieszanie kodu zarządzanego i niezarządzanego jest natomiast dobrym rozwiązaniem problemu przenoszenia aplikacji na platformę .NET. Proces ten może zostać rozłożony w czasie, a poszczególne fragmenty kodu mogą być zamieniane na kod zarządzany przy okazji ich naturalnej konserwacji związanej z wprowadzeniem nowych funkcji, algorytmów i rozwiązań. Dzięki temu - nawet mimo wielu różnic w stosunku do klasycznych technologii programistycznych - przejście na nową platformę może się okazać bardzo łagodne.