InteroperabilityEdit
Ponieważ systemy komputerowe powszechnie wymagają interakcji pomiędzy nowszymi i starszymi aplikacjami, .NET Framework zapewnia środki dostępu do funkcji zaimplementowanych w nowszych i starszych programach, które wykonują się poza środowiskiem .NET. Dostęp do komponentów Component Object Model (COM) jest zapewniony w przestrzeniach nazw System.Runtime.InteropServices
i System.EnterpriseServices
frameworka. Dostęp do innych funkcji odbywa się poprzez Platform Invocation Services (P/Invoke). Dostęp do funkcji .NET z aplikacji natywnych odbywa się poprzez odwrotną funkcję P/Invoke.
Niezależność językowaEdit
.NET Framework wprowadza Common Type System (CTS), który definiuje wszystkie możliwe typy danych i konstrukcje programistyczne obsługiwane przez CLR oraz to, jak mogą lub nie mogą współdziałać zgodnie ze specyfikacją CLI. Dzięki tej właściwości, .NET Framework wspiera wymianę typów i instancji obiektów pomiędzy bibliotekami i aplikacjami napisanymi przy użyciu dowolnego zgodnego języka .NET.
Bezpieczeństwo typówEdit
CTS i CLR używane w .NET Framework wymuszają również bezpieczeństwo typów. Zapobiega to źle zdefiniowanym rzutom, błędnym wywołaniom metod i problemom z wielkością pamięci podczas dostępu do obiektu. To również sprawia, że większość języków CLI jest statycznie typowana (z lub bez wnioskowania o typie). Jednakże, począwszy od .NET Framework 4.0, Dynamic Language Runtime rozszerzył CLR, pozwalając na implementację dynamicznie typowanych języków na szczycie CLI.
PrzenośnośćEdit
Mimo że Microsoft nigdy nie zaimplementował pełnego frameworka na żadnym systemie poza Microsoft Windows, zaprojektował go tak, aby był wieloplatformowy, a implementacje są dostępne dla innych systemów operacyjnych (zobacz Silverlight i § Alternatywne implementacje). Microsoft przekazał specyfikacje CLI (obejmujące biblioteki klas podstawowych, CTS i CIL), C# i C++/CLI zarówno organizacji Ecma International (ECMA), jak i International Organization for Standardization (ISO), udostępniając je jako oficjalne standardy. Umożliwia to stronom trzecim tworzenie kompatybilnych implementacji frameworka i jego języków na innych platformach.
SecurityEdit
.NET Framework posiada własny mechanizm bezpieczeństwa z dwiema ogólnymi cechami: Code Access Security (CAS), oraz walidację i weryfikację. CAS opiera się na dowodach, które są związane z konkretnym zespołem. Typowym dowodem jest źródło pochodzenia zespołu (czy jest on zainstalowany na lokalnej maszynie, czy też został pobrany z Internetu). CAS wykorzystuje dowody do określenia uprawnień przyznanych kodowi. Inny kod może zażądać, aby kod wywołujący uzyskał określone uprawnienia. Żądanie to powoduje, że CLR wykonuje obchód stosu wywołań: każdy zespół każdej metody w stosie wywołań jest sprawdzany pod kątem wymaganego uprawnienia; jeśli jakiemuś zespołowi nie zostanie przyznane uprawnienie, rzucany jest wyjątek bezpieczeństwa.
Zarządzany kod bajtowy CIL jest łatwiejszy do odtworzenia niż kod natywny, chyba że jest on obfuskowany. Programy dekompilujące .NET umożliwiają programistom nie posiadającym umiejętności inżynierii wstecznej przeglądanie kodu źródłowego znajdującego się za nieobfuskowanymi asemblacjami .NET. W przeciwieństwie do tego, aplikacje skompilowane do natywnego kodu maszynowego są znacznie trudniejsze do inżynierii wstecznej, a kod źródłowy prawie nigdy nie jest produkowany z powodzeniem, głównie z powodu optymalizacji kompilatora i braku refleksji. Powoduje to obawy w środowisku biznesowym o możliwą utratę tajemnic handlowych i omijanie mechanizmów kontroli licencji. Aby złagodzić te problemy, Microsoft od 2002 roku dołącza do Visual Studio .NET program Dotfuscator Community Edition. Narzędzia do obfuskacji innych firm są również dostępne u takich producentów, jak VMware, V.i. Labs, Turbo i Red Gate Software. Narzędzia szyfrujące na poziomie metod dla kodu .NET są dostępne od takich dostawców, jak SafeNet.
Zarządzanie pamięciąEdit
CLR uwalnia programistę od ciężaru zarządzania pamięcią (alokowanie i zwalnianie po zakończeniu); sam zajmuje się zarządzaniem pamięcią, wykrywając, kiedy pamięć może być bezpiecznie zwolniona. Instantyfikacje typów .NET (obiekty) są alokowane z zarządzanej sterty; puli pamięci zarządzanej przez CLR. Tak długo, jak istnieje referencja do obiektu, która może być bezpośrednia lub poprzez graf obiektów, obiekt jest uważany za używany. Gdy nie istnieje żadna referencja do obiektu i nie można do niego dotrzeć lub go użyć, staje się on śmieciem, kwalifikującym się do odebrania.
.NET Framework zawiera garbage collector (GC), który działa okresowo, w oddzielnym wątku od wątku aplikacji, który wylicza wszystkie nieużyteczne obiekty i odzyskuje przydzieloną im pamięć. Jest to niedeterministyczny, kompaktujący, mark-and-sweep garbage collector. GC uruchamia się tylko wtedy, gdy określona ilość pamięci została wykorzystana lub gdy w systemie jest wystarczający nacisk na pamięć. Ponieważ nie ma gwarancji, kiedy zostaną osiągnięte warunki do odzyskania pamięci, GC działa niedeterministycznie. Każda aplikacja .NET posiada zestaw korzeni, które są wskaźnikami do obiektów na stercie zarządzanej (obiekty zarządzane). Należą do nich referencje do obiektów statycznych, obiektów zdefiniowanych jako zmienne lokalne lub parametry metod w danym momencie oraz obiektów, do których odwołują się rejestry procesora. Podczas działania GC wstrzymuje działanie aplikacji, a następnie dla każdego obiektu, do którego odwołuje się root, wylicza rekursywnie wszystkie obiekty osiągalne z obiektów root i oznacza je jako osiągalne. Używa metadanych CLI i refleksji do odkrywania obiektów enkapsulowanych przez obiekt, a następnie rekurencyjnie je przemierza. Następnie wylicza wszystkie obiekty na stercie (które początkowo zostały zaalokowane przylegle) używając refleksji. Wszystkie obiekty nie oznaczone jako osiągalne są śmieciami. Jest to faza mark. Ponieważ pamięć zajmowana przez śmieci nie ma żadnego znaczenia, jest ona uważana za wolną przestrzeń. Pozostawia to jednak kawałki wolnej przestrzeni pomiędzy obiektami, które początkowo były przylegające. Obiekty te są następnie zagęszczane razem, aby wolna przestrzeń na zarządzanej stercie stała się ponownie przyległa. Każde odwołanie do obiektu unieważnione przez przeniesienie obiektu jest aktualizowane przez GC, aby odzwierciedlić nową lokalizację. Po zakończeniu odśmiecania aplikacja jest wznawiana. Najnowsza wersja .NET Framework wykorzystuje współbieżne odśmiecanie wraz z kodem użytkownika, dzięki czemu przerwy są niezauważalne, ponieważ odbywa się ono w tle.
Odśmiecanie używane przez .NET Framework jest również generacyjne. Obiekty mają przypisaną generację. Nowo utworzone obiekty są oznaczane jako Generacja 0. Obiekty, które przeżyją jedno odśmiecanie są oznaczane jako Generacja 1. Obiekty Generacji 1, które przeżyją kolejne odśmiecanie są oznaczane jako Generacja 2. Framework używa obiektów do Generacji 2. Obiekty wyższej generacji są odśmiecane rzadziej niż obiekty niższej generacji. Podnosi to efektywność zbierania śmieci, ponieważ starsze obiekty mają tendencję do dłuższego życia niż nowsze. Dzięki ignorowaniu starszych obiektów w większości przebiegów zbierania, w sumie potrzeba mniej sprawdzeń i operacji kompaktowania.
PerformanceEdit
Gdy aplikacja jest uruchamiana po raz pierwszy, .NET Framework kompiluje kod CIL do kodu wykonywalnego za pomocą swojego kompilatora just-in-time i buforuje program wykonywalny w .NET Native Image Cache. Dzięki buforowaniu, aplikacja uruchamia się szybciej przy kolejnych uruchomieniach, choć pierwsze uruchomienie jest zwykle wolniejsze. Aby przyspieszyć pierwsze uruchomienie, programiści mogą użyć narzędzia Native Image Generator do ręcznego skompilowania z wyprzedzeniem i zbuforowania dowolnej aplikacji .NET.
Odśmiecacz, który jest zintegrowany ze środowiskiem, może wprowadzać nieoczekiwane opóźnienia wykonania, nad którymi programista ma niewielką bezpośrednią kontrolę. „W dużych aplikacjach liczba obiektów, z którymi musi pracować garbage collector, może stać się bardzo duża, co oznacza, że odwiedzenie i ponowne uporządkowanie ich wszystkich może zająć bardzo dużo czasu.”
.NET Framework zapewnia wsparcie dla wywoływania Streaming SIMD Extensions (SSE) za pośrednictwem kodu zarządzanego od kwietnia 2014 roku w Visual Studio 2013 Update 2. Jednak Mono zapewniło wsparcie dla rozszerzeń SIMD od wersji 2.2 w przestrzeni nazw Mono.Simd w 2009 roku. Główny programista Mono, Miguel de Icaza, wyraził nadzieję, że to wsparcie SIMD zostanie przyjęte przez standard ECMA CLR. Strumieniowe rozszerzenia SIMD są dostępne w procesorach x86 od czasu wprowadzenia Pentium III. Niektóre inne architektury, takie jak ARM i MIPS, również posiadają rozszerzenia SIMD. W przypadku, gdy procesor nie obsługuje tych rozszerzeń, instrukcje są symulowane programowo.