Programowanie w języku Delphi » .NET

Podstawowa terminologia

Na samym początku, nim zaczniesz programować w .NET, należy objaśnić kilka terminów, którymi będę się posługiwał w tej kategorii.

Spis treści

     1 .NET ? nowe podejście do programowania
     2 Ewolucja platform programistycznych
     3 Podzespoły
     4 Język pośredni IL
     5 Manifest
     6 CLR
          6.1 Class Loader
          6.2 Weryfikacja
          6.3 Kompilator JIT
     7 CTS
     8 CLS
     9 Windows Forms
     10 Kod zarządzany i niezarządzany


  • Windows API (WinAPI) - programistyczny interfejs (ang. application programming interface), używanych w systemie operacyjnym Microsoft Windows. Innymi słowy specyfikacja procedur, funkcji służących do komunikacji z systemem operacyjnym.
  • Win16 - 16 bitowa wersja WinAPI.
  • Win32 - 32 bitowa wersja WinAPI używana w systemach Windows po dzień dzisiejszy. Jest to zbiór funkcji napisanych w języku C, które umiejscowione są w bibliotekach DLL - np. kernel32.dll, user32.dll itd.

Interfejs Win32 stanowi stary model programowania aczkolwiek dalej będzie on wspierany w systemie Windows - również w jego nowej wersji, której premiera przewidziana jest na 2007 rok (kodowa nazwa - Longhorn). Mimo tego, że z założenia WinAPI miało ułatwiać programowanie, wciąż pozostaje trudną platformą. Programowanie odbywa się na niskopoziomowych funkcjach (WinAPI jest stworzony w sposób strukturalny), dlatego też powstało wiele bibliotek obiektowych, które ułatwiają ten proces. Warto tu wspomnieć chociażby o MFC (ang. Microsoft Fundation Classes) lub VCL (ang. Visual Component Library), który wchodzi w skład produktów firmy Borland - Delphi i C++ Buildera.  

.NET ? nowe podejście do programowania


Platforma .NET została stworzona między innymi w celu ujednolicenia procesu programowania. Stanowi pewnego rodzaju rewolucję, całkowicie zmieniając dotychczasową wizję tworzenia aplikacji. Mimo, iż w .NET zostało zaimplementowanych wiele mechanizmów, znanych już wcześniej to i tak programiści muszą przywyknąć do wielu aspektów, wcześniej im nieznanych.

W .NET mamy do czynienia z bibliotekami klas, a nie z funkcjami. Proces programowania został także uproszczony, gdyż to właśnie .NET oraz podlegle mu mechanizmy biorą na siebie "odpowiedzialność" za sprawy, które wcześniej spoczywały na programiście.

Ewolucja platform programistycznych


Podsumujmy: w dotychczasowych najpopularniejszych systemach Windows (Windows 98/ME/XP) stosowany jest interfejs programistyczny zwany Win32 API (lub po prostu WinAPI) umożliwiający deweloperom tworzenie aplikacji pod system Windows. Ów interfejs, napisany w języku C, udostępnia wiele funkcji umożliwiających tworzenie okien, kontrolek itd.
Platforma, idea .NET nieco zmienia tę strategię, na której opierały się setki tysięcy aplikacji tworzonych pod system Windows. Oto udostępniono nam nowe biblioteki, klasy, funkcje oraz mechanizmy (m.in. CLR). Jednak ewolucja w stronę .NET nie kończy się na tym. Wraz z wprowadzeniem w 2007 roku nowego systemu operacyjnego Windows.NET (nazwa kodowa Longhorn) zmieni się całkowicie model projektowania ? dotychczasowy interfejs Win32 zostanie wyeliminowany, zastąpiony nowym ? WinFX. Rysunek poniżej przedstawia ewolucję platform, jaka nastąpiła w ciągu ostatnich lat.
 

Należy w tym momencie wprowadzić kolejne pojęcie, o którym nic wcześniej nie pisałem. Chodzi o nowy interfejs programistyczny (API), tworzony na podstawie .NET Framework, który zostanie wprowadzony w systemie Longhorn. Ów interfejs jest pisany całkowicie od nowa, pozbawiony zostanie wad poprzedniego Win32 oraz będzie obiektowy.
Dodatkowo WinFX będzie zapewniał całkowitą zgodność z Win32, dzięki czemu na Longhornie będą mogły być uruchamiane aplikacje napisane w dotychczasowym środowisku Windows.

Podzespoły


Wraz z .NET wiąże się pewne pojęcie, z którym często możesz się spotkać - mianowicie Assemblies, czyli podzespoły. W .NET podzespołem może być, i często jest zwykły plik z rozszerzeniem .exe lub .dll. Jest to pewien logiczny zbiór plików zawierający kod oraz zasoby aplikacji. Podzespół zawiera również manifest, który stanowi opis kodu.

Język pośredni IL


Języka Java zyskał sporą popularność głównie dlatego, iż może zostać uruchomiony na różnych platformach. Wszystko dzięki maszynom wirtualnym. Microsoft zaczerpnął ten pomysł do platformy .NET. Microsoft Intermediate Language (MSIL), bo to o nim mowa, stanowi pewnego rodzaju kod pośredni pomiędzy kodem źródłowym, a kodem maszynowym (wykonywalnym). Platforma .NET zawiera instrukcję umożliwiające kompilowanie na kod maszynowy i uruchamianie programów, zarządzanie i zwalnianie pamięci.

Możliwość wykonywania aplikacji .NET na procesorach innych niż Intel x86 daje perspektywy tworzenia programów na inne urządzenia jak telefony komórkowe, czy palmtopy.  

Kod IL przypomina nieco język Asemblera, fragment takiego kodu znajduje się poniżej:

.method family hidebysig virtual instance void 
        Dispose(bool Disposing) cil managed
{
  // Code size       30 (0x1e)
  .maxstack  2
  IL_0000:  ldarg.1
  IL_0001:  brfalse.s  IL_0016
  IL_0003:  ldarg.0
  IL_0004:  ldfld      class [System]System.ComponentModel.Container WinForm.TWinForm1::Components
  IL_0009:  brfalse.s  IL_0016
  IL_000b:  ldarg.0
  IL_000c:  ldfld      class [System]System.ComponentModel.Container WinForm.TWinForm1::Components
  IL_0011:  callvirt   instance void [System]System.ComponentModel.Container::Dispose()
  IL_0016:  ldarg.0
  IL_0017:  ldarg.1
  IL_0018:  call       instance void [System.Windows.Forms]System.Windows.Forms.Form::Dispose(bool)
  IL_001d:  ret
} // end of method TWinForm1::Dispose


Możliwe jest również jednorazowe skompilowanie danego programu od razu na kod maszynowy dzięki temu przy każdym uruchamianiem programu, oszczędzane są zasoby systemowe potrzebne na uruchomienie kompilatora JIT (ang. Just-In-Time) 1.

Manifest


Oprócz kodu pośredniego, w podzespole umieszczane są także informacje na jego temat. Jest to manifest, który z kolei zawiera tzw. metadane. Można powiedzieć, że metadane to opis kodu, lista parametrów funkcji, lista zmiennych oraz innych operacji. To wszystko umieszczane jest w jednym pliku PE (ang. Portable Executable) dając przy tym wrażenie zwykłej aplikacji wykonywalnej z rozszerzeniem *.exe.

Metadane są używane przez CLR do zarządzania pamięcią, weryfikacji danych oraz uruchamiania aplikacji. Informacje zawarte w metadanych pozwalają również na lokalizację klas, bibliotek potrzebnych do działania programu. Również kompilatory JIT wymagają informacji o klasach i bibliotekach do kompilacji i wykonania programu.

CLR


Wspólny język wykonywania, czyli Common Language Runtime (w skrócie CLR), to podstawowy komponent .NET Framework. CLR jest odpowiedzialny za uruchamianie programów, zarządzanie kodem i pamięcią. Zajmuje się również bezpieczeństwem danych, obsługą błędów oraz konwersją języka IL do postaci maszynowej.
Oto kilka punktów które przechodzi aplikacja od momentu, gdy użytkownik zarządzi jej uruchomienie:
  • Ładowanie klasy (ang. Class Loader)
  • Weryfikacja
  • Kompilacja

Class Loader


Dotychczas jedynym formatem rozpoznawanym przez systemy Windows jako aplikacja wykonywalna, był stary format PE. Stary format PE zawierał skompilowany kod maszynowy aplikacji. Instalując bibliotekę .NET w systemie dodawane jest uaktualnienie mówiące o nowym formacie PE, dzięki czemu system jest w stanie rozpoznać również nowy format plików wykonywalnych.

Skoro teraz aplikacja .NET jest rozpoznawana przez system, w momencie uruchamiania ten oddaje sterowanie do CLR. CLR odczytuje zawartość pliku oraz listę klas używanych w programie. Lista klas jest odczytywana z przeróżnych miejsc ? szczególnie jest to manifest oraz metadane, a także plik .config, który może być dołączany do programu. Po odczytaniu klasy, obliczona zostaje ilość pamięci potrzebnej, aby załadować klasy, a dopiero potem są one ładowane do pamięci.

Weryfikacja


Po załadowaniu klas do pamięci zawartość programu, czyli metadane oraz kod IL zostają poddane weryfikacji. Jest to ważny etap, gdyż w przypadku niepowodzenia kod IL nie zostanie przekazany kompilatorowi JIT.

Kompilator JIT


Kompilator JIT odgrywa znaczącą rolę w procesie uruchamiania aplikacji. Po weryfikacji kodu, przekazywany jest on do kompilatora, który kompiluje go do kodu maszynowego, a następnie gotowy program zostaje ładowany do pamięci. Przebywa w tej pamięci do czasu zakończenia jego działania.

Normalnie program w trakcie uruchamiania za każdym razem musi przechodzić proces kompilacji. Powoduje to nieco wolniejsze działanie aplikacji. Dlatego też raz uruchomiony program umieszczany jest w pamięci podręcznej (cache), tak więc jego ponowne uruchomienie spowoduje w rzeczywistości załadowanie skompilowanego już modułu z pamięci podręcznej.

CTS


Microsoft wprowadził pewną nowość w zakresie typów danych, nazwaną wspólnym systemem typów (ang. Common Type System). Polega ona na tym, że każdy język programowania wspierany przez platformę .NET posiada identyczne typy danych, programy mogą się więc wzajemnie integrować i wymieniać dane.

CLS


Common Language Specification (CLS) to jedna z najważniejszych części .NET. Jak dotąd każdy język programowania charakteryzował się zupełnie innymi (lub podobnymi) mechanizmami. Platforma .NET dostarcza programiście nowe mechanizmy, zarówno działające na najniższym poziomie systemu, zajmujące się obsługą pamięci itp. Dzięki CLS nie jest ważne w jakim języku programujemy, wykorzystujemy te same mechanizmy. Różnica leży jedynie w składni charakterystycznej dla danego języka. Przykładowo składnia w Visual Basic.NET różni się i to bardzo od składni C++. Nie jest jednak ważne, w jakim języku piszemy ? wykorzystujemy nazwy komend, klas o tej samej nazwie.

Windows Forms


Windows Forms (nazywana często w skrócie ? WinForms) to nowa biblioteka do wizualnego tworzenia aplikacji. Dzięki niej w prosty sposób możemy projektować wizualne aplikacje, korzystając ze standardowych kontrolek systemu Windows. Delphi 8 również wspiera WinForms, umożliwia wizualne projektowanie, tzn. korzystając z projektanta formularzy oraz palety narzędzi.

Kod zarządzany i niezarządzany


Platforma .NET definiuje dwa nowe pojęcia: kod zarządzany (managed code) oraz niezarządzany (ang. unmanaged code), które istotne są z punktu widzenia CLR. Kod niezarządzany to tradycyjny kod wykonywany poza środowiskiem .NET, czyli stare aplikacje kompilowane pod środowisko Win32. Natomiast jak nietrudno się domyśleć ? kod zarządzany to kod wykonywany pod kontrolą CLR.

Zmiany w Delphi 8 oraz w .NET są na tyle duże w porównaniu z Win32, że problemem staje się współdziałanie obu rodzajów aplikacji (aplikacji .NET oraz Win32), a także korzystanie z zasobów starszych aplikacji Win32 ? np. bibliotek DLL. Dlatego też w .NET w tym celu wykorzystujemy mechanizm zwany  marshalingiem  , który związany jest z określeniem w jaki sposób dane mają być przekazywane z kodu niezarządzanego do zarządzanego.


[1] Pierwsze uruchomienie aplikacji spowoduje kompilacje z kodu maszynowego przez kompilator JIT. Następnie wersja skompilowana jest zapisywana w specjalnej pamięci podręcznej. Każde kolejne uruchomienie programu spowoduje załadowanie wersji z pamięci cache.