Kilka słów o tym, czym jest .NET Framework

Znajomość funkcjonowania platformy .NET dla osoby programującej w języku C# jest niezbędna, jeśli chce ona być w pełni świadoma, jak działa po uruchomieniu napisany kod. Dla osób na co dzień niezwiązanych z tą platformą, postanowiłem napisać kilka słów mających na celu wyjaśnienie, czym właściwie ona jest.

Żeby lepiej zrozumieć sens istnienia i korzyści płynące z wykorzystania platformy .NET, warto zastanowić się nad historią i ewolucją dzisiejszych komputerów osobistych i serwerów. Cofnijmy się do lat 60. dwudziestego wieku, kiedy to powstawały tzw. komputery głównego szeregu, zwane również komputerami typu mainframe.

System mainframe z komputerem EC-1035. Źródło: https://pl.wikipedia.org/wiki/Mainframe#/media/File:Fotothek_df_n-11_0000385.jpg

 

Mówiąc pobieżnie, komputery te wykonywały programy napisane przez programistów na kartach, w języku assemblera, który był tłumaczony na kod maszynowy zrozumiały dla danego procesora. Każda instrukcja napisana przez programistę odpowiadała jednej instrukcji zrozumiałej dla procesora. Taki program bezpośrednio w instrukcjach operował na pamięci, rejestrach i urządzeniach wejścia / wyjścia maszyny. Program mógł wykonać dowolną operacje na komputerze, a zadaniem programisty było panować nad pamięcią, rejestrami itd. Były one pisane pod konkretny procesor – wykorzystanie tego samego programu pod innym procesorem było możliwe jedynie wtedy, kiedy posiadał on ten sam zestaw instrukcji.

Następnie przyszła epoka systemów operacyjnych, które tworzą warstwę pośredniczącą między poszczególnymi komponentami komputera, a programem użytkownika. Zawierają one elementy, które pozwalają lepiej i bezpieczniej korzystać z podzespołów komputera (np. mechanizm obsługi wielu wątków, pamięć wirtualna, system plików itd). Programy pisane pod systemy operacyjne nie odwołują się bezpośrednio do fizycznej pamięci czy procesora, ale korzystają z funkcji udostępnianych przez system operacyjny i za ich pośrednictwem wykorzystują fizyczne komponenty. Warstwa abstrakcji w postaci systemu operacyjnego pozwala nam nie martwić się o rodzaj procesora i poszczególnych komponentów. Jeśli są one obsługiwane przez dany system operacyjny, program powinien działać.

Z czasem jednak zaczęły powstawać coraz bardziej złożone aplikacje komputerowe, a udostępniane przez systemy operacyjne funkcje okazały się niewystarczające. Stąd też zrodziła się koncepcja środowisk uruchomieniowych dla wykonywania programów, które dodawały kolejną warstwę abstrakcji pomiędzy system operacyjny, a kod programisty. Pozwalają one na odizolowanie się on konkretnego systemu operacyjnego oraz wprowadzenie mechanizmów ułatwiających pisanie oprogramowania.

Idąc tym tokiem rozumowania, .NET Framework jest środowiskiem uruchomieniowym dla kodu, które ma ułatwić wytwarzanie oprogramowania. Platforma ta jest warstwą pośredniczącą pomiędzy systemem operacyjnym z rodziny Windows a wspieranym językiem programowania (wśród nich najpopularniejsze to C#, F# oraz Visual Basic). Klasa napisana w jednym ze wspieranych języków może być z powodzeniem wykorzystana w innym dzięki CTS (z ang. Common Type System) – standardowi, który określa jak definicje typów oraz wartości powinny być reprezentowane w pamięci. Platforma .NET Framework składa się z dwóch głównych komponentów – CLR (z ang. Common Language Runtime), który tworzy środowisko uruchomieniowe dla wykonywanego kodu, oraz bibliotek klas, które implementują typowe funkcjonalności wykorzystywane podczas wytwarzania oprogramowania (np. komunikacja z bazą danych, obsługa wątków, komunikacja sieciową).

Kompilacja kodu programisty do natywnego kodu

Znając już genezę tej platformy, warto zastanowić się jak w praktyce wygląda kompilacja kodu pisanego pod .NET Framework do kodu wykonywalnego przekazywanego do systemu operacyjnego. Na początku kod kompilowany jest do języka Intermediate Language, a następnie zapisywany na dysku w plikach zwanych assembly, z rozszerzeniami dll lub exe.

Następnie, w momencie uruchomienia tak skompilowanego pliku, system operacyjny bazując na metadanych pliku, uruchamia proces CLR, który po zainicjalizowaniu, ładuje kod w języku IL i wywołuje metodę początkową, kompilując w trakcie wykonywania fragmenty kodu IL do instrukcji maszynowych odpowiednich dla danej maszyny za pomocą mechanizmu JIT (just in time compilation). Oprócz JIT, CLR wywołując kod programisty, zapewnia również usługi takie jak odśmiecanie (z ang. Garbage Collection), obsługę wyjątków czy kontrole typów obiektów. Kod który jest wywoływany przez CLR nazywany jest kodem zarządzalnym. W programach mamy możliwość odwoływania się do kodu niezarządzalnego – polega to na wywoływaniu funkcji z już skompilowanych do kodu maszynowego komponentów, nie będących pod opieką CLR.

 

Proces tworzenia kodu wykonywalnego przy wykorzystaniu platformy .NET Framework. Źródłó: https://msdn.microsoft.com/en-us/library/z1zx9t92.aspx

 

Dzięki pośredniej kompilacji kodu do języka IL, nie ma znaczenia w jakim języku dany komponent został napisany – ważne, żeby istniał jego kompilator do języka IL. Pozwala to później odwoływać się do tego komponentu poprzez inny język programowania.

 

Materiały:

  1. .NET Platrom Guide
  2. Understanding .NET 2015
  3. NET Framework
  4. Common Type System
  5. Why is an assembly .exe file?
  6. Introduction to the C# Language and the .NET Framework
  7. J. Albahari, B. Albahari, „C# 6.0 w pigułce. Wydanie VI”. 1. Wprowadzenie do C# i .NET Framework, s. 17-27