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, Reflex, People, Hell, Hella, 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

Vybíráte herní periferii nebo hardware? Pak zapomeňte na nálepku Gaming

Vybíráte herní periferii nebo hardware? Pak zapomeňte na nálepku Gaming

** Herní hardware se od toho běžného často liší jen vzhledem ** Při výběru stále nezapomínejte na základní parametry ** Poradíme jak vybrat herní hardware i periferie

20.  2.  2017 | Stanislav Janů | 36

10 nejhorších produktů v historii Microsoftu

10 nejhorších produktů v historii Microsoftu

20.  2.  2017 | Karel Javůrek | 141

Pojďme programovat elektroniku: Žádný bastlíř se neobejde bez armády švábů

Pojďme programovat elektroniku: Žádný bastlíř se neobejde bez armády švábů

** Každý bastlíř se po čase neobjede bez armády švábů ** Dnes si některé z nich vyzkoušíme ** Třeba zázračný posuvný registr

19.  2.  2017 | Jakub Čížek | 40

AMD oficiálně představilo procesory Ryzen. Známe i jejich české ceny

AMD oficiálně představilo procesory Ryzen. Známe i jejich české ceny

** AMD uvedlo první tři procesory Ryzen 7 ** Všechny budou pracovat s osmi jádry a šestnácti vlákny ** Na pulty obchodů se dostanou už za týden

22.  2.  2017 | Stanislav Janů | 132

EU se děsí Windows 10. Prý o nás vědí až příliš. Microsoft chystá změny

EU se děsí Windows 10. Prý o nás vědí až příliš. Microsoft chystá změny

** Evropští úředníci chtějí, aby byly Desítky transparentnější ** Microsoft od jara skutečně chystá změny ** Ochráncům soukromí to ale nestačí

21.  2.  2017 | Jakub Čížek | 218

Remix Singularity: Microsoft si na tom vylámal zuby. Jak dopadne Android?

Remix Singularity: Microsoft si na tom vylámal zuby. Jak dopadne Android?

** Microsoft do svých telefonů integroval desktopové prostředí ** Moc to ale nevyšlo, chyběl pořádný výkon ** Teď to zkoušejí ex-googleři s Remix Singularity

23.  2.  2017 | Jakub Čížek | 73


Aktuální číslo časopisu Computer

Supertéma o počítačové bezpečnosti

AMD Ryzen přichází

Velké testy kinoprojektorů a levných špuntových sluchátek

Příslušenství do USB-C

reklama
reklama