Metadata a komponenty popisující samy sebe
V minulosti softwarová komponenta (.exe nebo .dll), která byla napsána v jednom jazyce, nemohla snadno použít softwarovou komponentu napsanou v jiném jazyce. Com poskytl krok k vyřešení tohoto problému. .NET usnadňuje spolupráci komponent tím, že kompilátorům umožňuje generovat další deklarativní informace do všech modulů a sestavení. Tyto informace, označované jako metadata, pomáhají komponentám bezproblémově pracovat.
Metadata jsou binární informace popisující váš program, který je uložený v souboru přenosných spustitelných souborů (PE) common language runtime nebo v paměti. Při kompilaci kódu do souboru PE se metadata vloží do jedné části souboru a váš kód se převede na běžný zprostředkující jazyk (CIL) a vloží se do jiné části souboru. Každý typ a člen definovaný a odkazovaný v modulu nebo sestavení je popsán v metadatech. Při spuštění kódu modul runtime načte metadata do paměti a odkazuje na něj, aby zjistil informace o třídách, členech, dědičnosti a tak dále.
Metadata popisují každý typ a člen definovaný v kódu jazykově neutrálním způsobem. Metadata ukládají následující informace:
Popis sestavení.
Identita (název, verze, jazyková verze, veřejný klíč).
Typy, které jsou exportovány.
Jiná sestavení, na které toto sestavení závisí.
Oprávnění zabezpečení potřebná ke spuštění
Popis typů
Implementované názvy, viditelnosti, základní třídy a rozhraní.
Členy (metody, pole, vlastnosti, události, vnořené typy).
Atributy.
- Další popisné prvky, které upravují typy a členy.
Výhody metadat
Metadata jsou klíčem k jednoduššímu programovacímu modelu a eliminují potřebu souborů IDL (Interface Definition Language), hlavičkových souborů nebo jakékoli externí metody odkazu na komponenty. Metadata umožňují, aby se jazyky .NET popisovaly automaticky jazykově neutrálním způsobem, který není vidět vývojářem i uživatelem. Metadata je navíc rozšiřitelná prostřednictvím použití atributů. Metadata poskytují následující hlavní výhody:
Samopopisující soubory
Moduly a sestavení modulu CLR (Common Language Runtime) jsou popsány vlastním popisem. Metadata modulu obsahují všechno potřebné k interakci s jiným modulem. Metadata automaticky poskytují funkce IDL v modelu COM, takže můžete použít jeden soubor pro definici i implementaci. Moduly a sestavení modulu runtime nevyžadují ani registraci v operačním systému. V důsledku toho popisy používané modulem runtime vždy odrážejí skutečný kód v kompilovaném souboru, což zvyšuje spolehlivost aplikace.
Interoperabilita jazyků a jednodušší návrh založený na komponentách.
Metadata poskytují všechny informace potřebné ke zkompilovanému kódu, abyste mohli dědit třídu ze souboru PE napsaného v jiném jazyce. Můžete vytvořit instanci jakékoli třídy napsané v libovolném spravovaném jazyce (libovolném jazyce, který cílí na modul CLR), aniž byste se museli starat o explicitní zařazování nebo používání vlastního kódu interoperability.
Atributy.
.NET umožňuje deklarovat v kompilovaném souboru konkrétní druhy metadat, označovaných jako atributy. Atributy najdete v rozhraní .NET a slouží k podrobnějšímu řízení chování programu za běhu. Kromě toho můžete do souborů .NET vygenerovat vlastní metadata prostřednictvím uživatelsky definovaných vlastních atributů. Další informace naleznete v tématu Atributy.
Metadata a struktura přenositelného spustitelného souboru
Metadata jsou uložena v jedné části přenosného spustitelného souboru .NET (PE), zatímco běžný zprostředkující jazyk (CIL) je uložen v jiné části souboru PE. Část souboru metadat obsahuje řadu tabulek a datových struktur haldy. Část CIL obsahuje tokeny CIL a metadat, které odkazují na část metadat souboru PE. Tokeny metadat můžete narazit například při použití nástrojů, jako je IL Disassembler (Ildasm.exe), k zobrazení souboru CIL vašeho kódu.
Tabulky metadat a haldy
Každá tabulka metadat obsahuje informace o prvech programu. Například jedna tabulka metadat popisuje třídy v kódu, druhá tabulka popisuje pole atd. Pokud máte v kódu deset tříd, tabulka tříd bude mít desítky řádků, jednu pro každou třídu. Tabulky metadat odkazují na jiné tabulky a haldy. Například tabulka metadat pro třídy odkazuje na tabulku pro metody.
Metadata také ukládají informace ve čtyřech strukturách haldy: řetězec, objekt blob, uživatelský řetězec a identifikátor GUID. Všechny řetězce používané k pojmenování typů a členů jsou uloženy v haldě řetězce. Například tabulka metod neukládá přímo název konkrétní metody, ale odkazuje na název metody uložené v haldě řetězce.
Tokeny metadat
Každý řádek každé tabulky metadat je jedinečně identifikován v části souboru PE CIL tokenem metadat. Tokeny metadat jsou koncepčně podobné ukazatelům, které jsou trvalé v CIL, které odkazují na konkrétní tabulku metadat.
Token metadat je čtyřbajtů. Horní bajt označuje tabulku metadat, na kterou konkrétní token odkazuje (metoda, typ atd.). Zbývající tři bajty určují řádek v tabulce metadat, která odpovídá programovacímu prvku, který je popsán. Pokud definujete metodu v jazyce C# a zkompilujete ji do souboru PE, může v části souboru PE existovat následující token metadat:
0x06000004
Horní bajt (0x06
) označuje, že se jedná o token MethodDef . Nižší tři bajty () říká modulu CLR (000004
Common Language Runtime), aby se podíval na čtvrtý řádek tabulky MethodDef s informacemi popisovanými touto definicí metody.
Metadata v rámci souboru PE
Při kompilaci programu pro modul CLR (Common Language Runtime) se převede na soubor PE, který se skládá ze tří částí. Následující tabulka popisuje obsah jednotlivých částí.
Oddíl PE | Obsah oddílu PE |
---|---|
Hlavička PE | Index hlavních oddílů souboru PE a adresa vstupního bodu. Modul runtime tyto informace používá k identifikaci souboru jako souboru PE a k určení, kde se při načítání programu do paměti spustí spuštění. |
Pokyny pro CIL | Pokyny microsoftu pro zprostředkující jazyk (CIL), které tvoří váš kód. Mnoho instrukcí CIL je doprovázeno tokeny metadat. |
Metadata | Tabulky a haldy metadat Modul runtime používá tento oddíl k zaznamenání informací o každém typu a členu kódu. Tato část obsahuje také vlastní atributy a informace o zabezpečení. |
Používání metadat v době běhu
Pokud chcete lépe porozumět metadatům a jeho roli v modulu CLR (Common Language Runtime), může být užitečné vytvořit jednoduchý program a ilustrovat, jak metadata ovlivňují dobu běhu. Následující příklad kódu ukazuje dvě metody uvnitř třídy volaný MyApp
. Metoda Main
je vstupní bod programu, zatímco Add
metoda jednoduše vrátí součet dvou celých argumentů.
Public Class MyApp
Public Shared Sub Main()
Dim ValueOne As Integer = 10
Dim ValueTwo As Integer = 20
Console.WriteLine("The Value is: {0}", Add(ValueOne, ValueTwo))
End Sub
Public Shared Function Add(One As Integer, Two As Integer) As Integer
Return (One + Two)
End Function
End Class
using System;
public class MyApp
{
public static int Main()
{
int ValueOne = 10;
int ValueTwo = 20;
Console.WriteLine("The Value is: {0}", Add(ValueOne, ValueTwo));
return 0;
}
public static int Add(int One, int Two)
{
return (One + Two);
}
}
Při spuštění kódu modul runtime načte do paměti a projděte si metadata pro tuto třídu. Po načtení modul runtime provede rozsáhlou analýzu datového proudu CIL (Common Intermediate Language) metody, který ho převede na rychlé nativní pokyny počítače. Modul runtime používá kompilátor JIT (just-in-time) k převodu instrukcí CIL na nativní strojový kód po jedné metodě podle potřeby.
Následující příklad ukazuje část CIL vytvořené z předchozí funkce kódu Main
. Pomocí nástroje CIL Disassembler (Ildasm.exe) můžete zobrazit CIL a metadata z libovolné aplikace .NET.
.entrypoint
.maxstack 3
.locals ([0] int32 ValueOne,
[1] int32 ValueTwo,
[2] int32 V_2,
[3] int32 V_3)
IL_0000: ldc.i4.s 10
IL_0002: stloc.0
IL_0003: ldc.i4.s 20
IL_0005: stloc.1
IL_0006: ldstr "The Value is: {0}"
IL_000b: ldloc.0
IL_000c: ldloc.1
IL_000d: call int32 ConsoleApplication.MyApp::Add(int32,int32) /* 06000003 */
Kompilátor JIT čte kód CIL pro celou metodu, důkladně ho analyzuje a generuje efektivní nativní instrukce pro metodu. Při IL_000d
, metadata token pro metodu Add
(/*
06000003 */
) je zjištěn a modul runtime používá token ke konzultaci třetí řádek tabulky MethodDef .
Následující tabulka ukazuje část tabulky MethodDef odkazované tokenem metadat, který popisuje metodu Add
. Zatímco ostatní tabulky metadat existují v tomto sestavení a mají vlastní jedinečné hodnoty, je popsána pouze tato tabulka.
Řádek | Relativní virtuální adresa (RVA) | ImplFlags | Příznaky | Název (Odkazuje na haldu řetězce.) |
Podpis (odkazuje na haldu objektu blob.) |
---|---|---|---|---|---|
0 | 0x00002050 | IL Spravované |
Veřejná Znovu použítSlot SpecialName RTSpecialName .ctor |
.ctor (konstruktor) | |
2 | 0x00002058 | IL Spravované |
Veřejná staticky. Znovu použítSlot |
Hlavní | String |
3 | 0x0000208c | IL Spravované |
Veřejná staticky. Znovu použítSlot |
Přidání | int, int, int |
Každý sloupec tabulky obsahuje důležité informace o kódu. Sloupec RVA umožňuje modulu runtime vypočítat počáteční adresu paměti CIL, která definuje tuto metodu. Sloupce ImplFlags a Flags obsahují bitové masky , které popisují metodu (například zda je metoda veřejná nebo soukromá). Sloupec Name indexuje název metody z haldy řetězce. Sloupec Signature indexuje definici podpisu metody v haldě objektu blob.
Modul runtime vypočítá požadovanou adresu posunu ze sloupce RVA ve třetím řádku a vrátí tuto adresu kompilátoru JIT, který pak pokračuje na novou adresu. Kompilátor JIT pokračuje ve zpracování souboru CIL na nové adrese, dokud nenarazí na jiný token metadat a proces se opakuje.
Pomocí metadat má modul runtime přístup ke všem informacím, které potřebuje k načtení kódu, a zpracování do nativních instrukcí počítače. Tímto způsobem metadata umožňují samopis souborů a společně se systémem běžných typů dědičnost mezi jazyky.