Poznáváme C# a Microsoft.NET 36. díl – úvod do reflexe

V tomto dílu se začneme věnovat dle mého názoru velmi zajímavou problematikou, kterou je takzvaná reflexe. Pomocí reflexe je totiž možné za běhu programu dynamicky zjišťovat informace o existujících typech.

Aplikace v .NET frameworku

Předtím než se podíváme přímo na problematiku reflexe v .NET bude dobré, když se alespoň stručně zmíním o tom, z jakých částí jsou aplikace vlastně tvořeny. Jak již bylo v seriálu zmíněno základním zaveditelným prvkem aplikace pro .NET framework je Assembly (Sestava). Assembly mimo to také tvoří základní jednotku pro správu verzí, jednotné rozlišování typů a specifikaci bezpečnostních oprávnění.

Každá aplikace pro .NET framework je tvořena přinejmenším jednou assembly a ta je zase tvořena čtyřmi částmi, kterými jsou:

  • manifest, který obsahuje metadata o assembly
  • metadata o typech obsažených v assembly
  • kód v jazyce MSIL, který je spuštěn prostředím .NET runtime
  • zdroje (resources)

Metadata o obsažených typech a MSIL kód spolu tvoří takzvaný modul, což je přenositelný spustitelný (PE – portable executable) soubor. Nejjednodušší assembly jsou složeny z manifestu a jediného modulu s typy aplikace. I když to není časté, tak je možné vytvořit i sestavu s více moduly. Jednotlivé moduly s typy jsou pak představovány soubory s příponou .netmodule. Takovéto assembly jsou většinou tvořeny z optimalizačních důvodů, protože prostředí .NET runtime nahrává moduly pouze v případě potřeby typu v nich obsažených.

Možná se někteří z vás pozastavili na pojmem metadata. Nejedná se o nic jiného než o data, která nesou popisné informace o assembly či typu. Například manifest obsahuje mimo jiné tato metadata:

  • jednoduchý název assembly
  • číslo verze assembly
  • veřejný klíč tvůrce a hešový kód assembly (volitelně)
  • seznam souborů, které tvoří danou assembly a jejich hešové kódy
  • seznam typů, které tvoří assembly a informaci ke kterému modulu v assembly je konkrétní typ připojen

Reflexe v .NET

Jedním z důsledků použití mechanismu metadat pro všechny typy v prostředí .NET frameworku je možnost tyto typy v našem programu prozkoumávat a tato věc je nazývána reflexe. Jmenný prostor, který obsahuje nemalý počet tříd, jež námi mohou být použity pro manipulaci s danými elementy konkrétní aplikace nese název System.Reflection.

Mechanismus reflexe nám tedy umožňuje procházení a manipulaci s objektovým modelem představující konkrétní aplikaci. Metadata, která jsou reflexí využívána jsou obvykle vytvářena kompilátorem při překladu aplikace. Kromě tohoto obvyklého způsoby tvorby metadat k elementům aplikace, je možné metadata vytvořit pomocí tříd, které se nacházejí ve jmenném prostoru System.Reflection.Emit.

Každá aplikace pro .NET framework běží v nějaké aplikační doméně, představující izolované běhové prostředí. Aplikační doménu je možné brát jako obdobu procesu ze světa programování ve Win32. Aplikační doména sama o sobě není popsána metadaty. Aplikační doména je představována třídou AppDomain, která nám pomocí své statické vlastnosti CurrentDomain předloží přístup k aktuální aplikační doméně aplikace a pokud na ní zavoláme metodu GetAssemblies získáme v podobě pole všechny instance třídy Assembly, která reflektuje objekt assembly v aplikační doméně. A stejně jako třída Assembly reflektuje assembly v aplikační doméně, tak ve jmenném prostoru System.Reflection existují i další třídy, které reflektují ostatní elementy aplikace .NET . Pro lepší pochopení vztahů mezi těmito reflektujícími třídami jsem zhotovil jednoduchý UML diagram, který tyto třídy a jejich vztahy zobrazuje.

Klepněte pro větší obrázek

Jak můžeme vidět, tak třemi základní typy v reflexi jsou třídy Module, MemberInfo a Assembly. Co reflektují třídy Module a Assembly je jasné již z jejich názvu .Třída MemberInfo je třídou abstraktní a představuje předka pro třídy, které poskytují informace o členech třídy. Jedním z potomků této třídy je další abstraktní třída MethodBase, která je předkem pro třídy ConstructorInfo a MethodInfo, které, jak název napovídá, poskytují informace o konstruktorech respektive metodách třídy.

Třída Type ze jmenného prostoru System, která je taktéž jedním z potomků abstraktní třídy MemberInfo a je asi nejzákladnějším typem reflexe. Tato třída představuje informaci o daném typu, jinými slovy představuje jeho metadata. Na úvod do mechanismu reflexe jsem vytvořil jednoduchý příklad, ve kterém je pouze získána instance třídy Type a pomocí ní jsou zjištěny všechny členy. Abych na ukázku nepoužíval pouze vestavěné typy .NET frameworku, tak jsem kvůli příkladu vytvořil ještě jednoduchou třídu Osoba.

/// <summary>
/// Trida predstavujici osobu, ktera bude pouzita v
/// uvodnim prikladu na pouziti reflexe
/// </summary>
public class Osoba
{
  private string jmeno;
  private string prijmeni;
  private DateTime datumNarozeni;

  public string Jmeno
  {
    get{return jmeno;}
    set{jmeno = value;}
  }

  public string Prijmeni
  {
    get{return prijmeni;}
    set{prijmeni = value;}
  }
  public DateTime DatumNarozeni
  {
    get{return datumNarozeni;}
    set{datumNarozeni = value;}
  }
   
  public Osoba(){}

  public int VypocistVek()
  {
    TimeSpan lSpan = DateTime.Now - datumNarozeni;
    return lSpan.Days / 365;
  }
}

/// <summary>
/// Uvodni priklad pouziti reflexe
/// </summary>
public class PrikladReflexe
{
  public static void VypisCleny(Type Typ)
  {
    Console.WriteLine("Vypisuji vlastnosti typu {0}",Typ.Name);
    //ziskani vsech clenu
    MemberInfo[] lSeznamClenu = Typ.GetMembers();
    foreach(MemberInfo lInfo in lSeznamClenu)
    {
      Console.WriteLine("Nazev clenu = {0} - druh clenu = {1}", lInfo.Name,lInfo.MemberType);
    }
  }

  public static void Priklad()
  {
    Osoba lOsoba = new Osoba();
    //ziskani instance tridy Type pomoci metody GetType
    Type lTypOsoba = lOsoba.GetType();
    //ziskani instance tridy Type pomoci staticke Metody
    //GetType tridy type
    Type lTypInt32 = Type.GetType("System.Int32");
    //ziskani instance tridy Type pouzitim operatoru typeof
    Type lTypString = typeof(string);

    VypisCleny(lTypOsoba);
    VypisCleny(lTypInt32);
    VypisCleny(lTypString);
  }
}

Jak můžeme v příkladu vidět, instanci třídy System.Type je možné získat třemi způsoby. Tím prvním je zavoláním metody GetType na konkrétní instanci třídy jejíž popis chceme získat. Druhým způsobem je použití statické metody GetType třídy System.Type, jíž jako parametr zadáme řetězec představující plně kvalifikovaný název třídy (to znamená název třídy včetně jmenného prostoru do něhož spadá). Třetím a podle mých informací i drobek rychlejším řešením získání instance třídy System.Type je použítí operátoru typeof jazyka C#.

Příští díl se již podrobněji podíváme na jednotlivé reflektující třídy.

Zdrojové kódy k příkladům jsou ke stažení zde.

Diskuze (2) Další článek: Žádost Applu o patentování iPodu zamítnuta, rychlejší byl Microsoft

Témata článku: Software, Microsoft, Programování, Reflex, Jednoduchý typ, Private, Metadata, Framework, Díl, Nemalý počet, Public, Zavolání, Microsoft NET, LSE


Určitě si přečtěte

Není jen Flightradar: Našli jsme další aplikace pro sledování letadel, některé ukážou i víc

Není jen Flightradar: Našli jsme další aplikace pro sledování letadel, některé ukážou i víc

** 8 služeb pro sledování leteckého provozu ** Nejznámější je Flightradar24, ale alternativy leckdy prozradí více ** Letadla i v této pohnuté době čile létají a je co pozorovat

Karel Kilián | 13

Filmové pirátství asi jen tak nezmizí. Když už musíte, stahujte bezpečně v Seedru

Filmové pirátství asi jen tak nezmizí. Když už musíte, stahujte bezpečně v Seedru

** Máme HBO Go, máme Netflix... ** Ale stejně krademe filmy a seriály ** Když už musíte, stahujte torrenty bezpečně v Seedru

Jakub Čížek | 141


Aktuální číslo časopisu Computer

Megatest mobilů do 8 000 Kč

Test bezdrátových headsetů

Linux i pro začátečníky

Jak surfovat anonymně