reklama

Poznáváme C# a Microsoft.NET 39. díl – další použití reflexe

Dnešní díl, který je posledním dílem, ve kterém se budu zabývat reflexí, bude věnován použití reflexe pro vytváření instancí za běhu jiným způsobem než použitím třídy Activator. Také si ukážeme funkci polymorfizmu v reflexi a nakonec poodhalím některé třídy ze jmenného prostoru System.Relfection.Emit pro vytváření nových typů za běhu.

Použití třídy ConstructorInfo

Dosud jsme v našich příkladech, kde jsme vytvářeli instance jednotlivých typů pomocí reflexe používali třídu Activator a její metodu CreateInstance. Kromě tohoto způsobu, můžeme využít i třídu ConstructorInfo, která slouží k reflexi konstruktorů daného typu. Jelikož je tato třída potomkem abstraktní třídy MethodBase obsahuje, stejně jako nám již známá třída MethodInfo, metodu Invoke, která v případě třídy ConstructorInfo vyvolá určitý konstruktor (pokud je takový nalezen). Následující příklad ukazuje použití této třídy na ukázkové třídě Zamestnanec.

/// <summary>
/// Ukazkova trida, ktera bude pozdeji instancovana pomoci reflexe
/// </summary>
public class Zamestnanec
{
  private string jmeno;
  private string prijmeni;
  private int hodinovaMzda;

  public string Jmeno
  {
    get{return jmeno;}
  }
  public string Prijmeni
  {
    get{return prijmeni;}
  }
  public int HodinovaMzda
  {
    get{return hodinovaMzda;}
    set{hodinovaMzda = value;}
  }

  public Zamestnanec(string jmeno, string prijmeni, int hodinovaMzda)
  {
    this.jmeno = jmeno;
    this.prijmeni = prijmeni;
    this.hodinovaMzda = hodinovaMzda;
  }

  public void VypisMzdu(int pocetHodin)
  {
    Console.WriteLine(pocetHodin * hodinovaMzda);
  }
}
/// <summary>
/// Ukazka vytvoreni instance pomoci reflexe pouzitim tridy ConstructorInfo
/// </summary>
public class ConstructorInfoPriklad
{
  public static void VytvoritZamestnance()
  {
    Type lZamType = typeof(Zamestnanec);
    //vytvoreni seznamu typu parametru pro nalezeni konkretniho konstruktoru
    Type[] lParamTypes = new Type[3];
    lParamTypes[0] = typeof(string);
    lParamTypes[1] = typeof(string);
    lParamTypes[2] = typeof(int);
    //hledame instancni, verejne konstruktory
    BindingFlags lFlags = BindingFlags.Instance | BindingFlags.Public;
    ConstructorInfo lConstInfo = lZamType.GetConstructor(lFlags,null,lParamTypes,null);
    //vyvolani kostruktoru spolu s predanim parametru
    Zamestnanec lInstance = (Zamestnanec) lConstInfo.Invoke(new object[]{"Jan","Novak",100});
    lInstance.VypisMzdu(160);
  }
 
}

Vyvolání konstruktoru použitím metody Invoke je v zásadě stejné jako v případě použití u třídy MethodInfo, takže musíme pomocí pole instancí třídy Type specifikovat jakou verzi konstruktoru hledáme a pak pomocí pole objektů předat metodě Invoke hodnoty těchto parametrů.

Reflexe a polymorfizmus

Polymorfizmus je jayzce C# využíván nejen v případě standardních volání, ale i při používání reflexe. V následujícím příkladu je toto ukázáno na vytvoření abstraktní třídy Osoba, která obsahuje definici pro jednu abstraktní metodu. Třída má dva potomky, které její abstraktní metodu implementují. Zdrojový kód ukázkových tříd vypadá takto:

/// <summary>
/// Bazova trida pro osoby
/// </summary>
public abstract class Osoba
{
  public abstract void RekniPozdrav();
}

public class CeskaOsoba : Osoba
{
  public override void RekniPozdrav()
  {
    Console.WriteLine("Ahoj lidi");
  }

}

public class AnglickaOsoba : Osoba
{
  public override void RekniPozdrav()
  {
    Console.WriteLine("Hello people");
  }
 
}

Vlastní příklad získá za běhu assembly, která obsahuje definici výše uvedených typů, projde všechny typy v ní obsažené a zkoumá, zda-li je konkrétní typ potomkem třídy Osoba. V případě, že je tomu tak, je vytvořena instance typu a zavolána na něm metoda RekniPozdrav. Zdrojový kód je takovýto :

/// <summary>
/// Ukazka pouziti polymorfismu (pozdni vazby) v reflexi
/// </summary>
public class PolymofismusPriklad
{
  public static void Pozdravy()
  {
    //ziskani nasi assembly
    Assembly lAssembly = Assembly.Load("PrikladyZive39");
    foreach(Type lType in lAssembly.GetTypes())
    {
      //pokud je aktualni typ potomkem tridy Osoba vyvolame
      //na jeho instanci metodu RekniPozdrav
      if (lType.IsSubclassOf(typeof(Osoba)) )
      {
        Osoba lInstance = (Osoba) Activator.CreateInstance(lType);
        MethodInfo lMethod = lType.GetMethod("RekniPozdrav");
        lMethod.Invoke(lInstance,null);
      }
    }
     
  }
}

Výstup, jež po spuštění uvidíte a který jistě očekáváte je samozřejmě tento:

Ahoj lidi
Hello people

Dynamické vytváření nových elementů aplikace pomocí reflexe

Na závěr našeho několikadílného povídání o reflexi, bych zde rád čtenářům poskytl náhled na o něco složitější funkci reflexe, kterou je dynamické vytváření jednotlivých elementů aplikace (assembly, moduly, typy, členy typů) za jejího běhu. Jmenný prostor, který obsahuje třídy umožňující vytvářet nová metadata a kód MSIL nese název System.Reflection.Emit. Nejprve uvedu příklad, který v aktualní aplikační doméně vytvoří novou assembly, modul, v modulu dynamický typ a v něm metodu, potom příklad podrobněji popíšu.

/// <summary>
/// Ukazka vytvoreni novych elementu aplikace za behu
/// </summary>
public class EmitPriklad
{
  public static void VytvoreniTypu()
  {
    //Ziskani aplikacni domeny
    AppDomain lCurrentDomain = AppDomain.CurrentDomain;
    //vytvoreni jmena pro assembly
    AssemblyName lAssemblyName = new AssemblyName();
    lAssemblyName.Name = "DynamickaAssembly";
    //vytvoreni dynamicke assembly
    AssemblyBuilder lAssemblyBuilder = lCurrentDomain.DefineDynamicAssembly(lAssemblyName,AssemblyBuilderAccess.Run);
    //vytvoreni modulu
    ModuleBuilder lModuleBuilder = lAssemblyBuilder.DefineDynamicModule("DynamickyModul");
    //vytvoreni typu
    TypeBuilder lTypeBuilder = lModuleBuilder.DefineType("DynamickyTyp",TypeAttributes.Public);
    //vytvoreni metody
    MethodBuilder lMethodBuilder = lTypeBuilder.DefineMethod("DynamickaMetoda",MethodAttributes.Public | MethodAttributes.Virtual,typeof(void),null);
    //vytvoreni IL kody predstavujici telo metody
    ILGenerator lGenerator = lMethodBuilder.GetILGenerator();
    lGenerator.EmitWriteLine("Vypsani pomoci dynamicke metody");
    lGenerator.Emit(OpCodes.Ret);
    //finalni vytvoreni typu
    lTypeBuilder.CreateType();
    //ziskani instance System.Type pro nas typ
    Type lDynamicType = lModuleBuilder.GetType("DynamickyTyp");
    object lInstance = Activator.CreateInstance(lDynamicType);
    //vyvolani metody
    lDynamicType.GetMethod("DynamickaMetoda").Invoke(lInstance,null);
  }
}

Předtím než se pustíme do vytváření nové dynamické assembly v aplikační doméně, musíme nejdříve pomocí instance třídy AssemblyName vytvořit její název. Pokud nám stačí assembly přiřadit pouze jednoduchý název, využijeme k tomu implicitní konstruktor a po té nastavíme instanční vlastnosti Name. Pokud jsme tak učinili, můžeme již použitím metody DefineDynamicAssembly na instanci třídy AppDomain na základě jména vytvořit novou assembly.

Kromě jména assembly metodě ještě formou parametru předáme přístupový mód možné použití dynamické assembly a to pomocí výčtu AssemblyBuilderAccess. V našem příkladu je použita hodnota Run, která vytvářenou assembly umožňuje pouze spouštět, nikoliv ji však uložit na disk. Metoda DefineDynamicAssembly vrací odkaz na objekt typu AssemblyBuilder, který představuje dynamickou assembly.

Na tomto objektu je následně zavoláním metody DefineDynamicModule vytvořen nový modul se specifickým jménem. Zavoláním této metody dostaneme odkaz na instanci třídy ModuleBuilder, pomocí níž analogickým způsobem vytvoříme novou definici typu (metoda DefineType) a použitím výčtu TypeAttributes řekneme, že se jedná o typ veřejně přístupný.

Na instanci třídy TypeBuilder, pomocí metody DefineMethod definuje v typu novou metodu a výčtem MethodAttributes specifikujeme, že metoda je veřejná a virtuální. Po té získáme generátor mezikódu IL (ILGenerator) pro definici těla metody. Pomocí metody EmitWriteLine zajistíme vygenerování IL kódu, který odpovídá příkazu Console.WriteLine v C#. Pro ukončení metody musíme vygenerovat odpovídající IL kód.

To zajistíme metodou Emit třídy ILGenerator, jíž předáme instanci třídy OpCodes, která ve formě svých statických datových členů poskytuje prostředek pro reprezentaci IL kódu pro jednotlivé akce. V našem příkladu je použit statický datový člen OpCodes.Ret, který reprezentuje IL kód právě pro konec těla metody. Pro ukončení vytvoření nového typu použijeme metodu CreateType třídy TypeBuilder. Nakonec je získána instance třídy System.Type, vytvořena instance a zavolána definovaná metoda.

Zdrojové kódy k příkladům naleznete zde.

Témata článku: Software, Microsoft, Programování, Public, People, Hello, Kody

5 komentářů

Nejnovější komentáře

  • Pavel Polívka 24. 11. 2007 13:36:49
    Programovou oflline verzi seriálu naleznete ke stažení na...
  • Libor 8. 1. 2007 11:07:35
    ...
    public static MyForm myForm = null;
  • Libor 8. 1. 2007 11:06:57
    Možná že se pletu, ale nešlo by to zveřejněním handle...
reklama
Určitě si přečtěte

UPC překopli páteřní kabel. V Brně i druhý den nejede internet ani kabelovka

UPC překopli páteřní kabel. V Brně i druhý den nejede internet ani kabelovka

** V Brně byl velký výpadek služeb UPC ** Důvodem je překopnutý páteřní kabel ** V některých lokalitách služby stále nefungují

5.  12.  2016 | Jakub Čížek | 103

17 expertek Microsoftu předpovědělo rok 2027. Splní se alespoň něco?

17 expertek Microsoftu předpovědělo rok 2027. Splní se alespoň něco?

** Zmizí klasické vyhledávače ** Budeme programovat buňky ** Kvantové počítače překonají šifry

6.  12.  2016 | Jakub Čížek | 36

11 tipů na dobrý stolní počítač: od základu po herní mašiny

11 tipů na dobrý stolní počítač: od základu po herní mašiny

** Postavte si stolní počítač! Máme pro vás 11 vzorových sestav s rozpisem komponent ** Většina tipů cílí na hráče, věnujeme se ale i základnímu PC a počítačům na střih videa ** Nadělte si nový počítač třeba pod stromeček

5.  12.  2016 | Adam Kahánek | 74

Nejlepší notebooky nad 20 tisíc: poradíme, které teď chcete

Nejlepší notebooky nad 20 tisíc: poradíme, které teď chcete

** V notebooku s cenou nad 20 tisíc nesmí chybět kvalitní displej a rychlé úložiště ** Za dalších deset tisíc můžete dostat navíc styl nebo výkonnější komponenty ** Vybírat můžete z různých velikostí i konstrukcí

8.  12.  2016 | Stanislav Janů | 85


reklama