Mnohé ze služeb platformy .NET (jako pozdní vazba, serializace, vzdálené řízení, atributy a podobně) závisejí na přítomnosti metadat. Vytvářené programy mohou využívat tato metadata a rozšiřovat je o nové informace. Reflexí je označováno prozkoumávání existujících typů prostřednictvím metadat. Uskutečňuje se prostřednictvím sady typů v oboru názvů System.Reflection
. Je rovněž možné dynamicky vytvářet nové typy pomocí tříd v oboru názvů System.Reflection.Emit
. Reflexe představuje procházení a manipulování s objektovým modelem, který představuje nějakou aplikaci včetně všech jejích elementů kompilace a běhu.
Základní jednotkou aplikace jsou její typy obsahující členy a vnořené typy. Typy jsou v modulech a ty obvykle v sestavách. Všechny tyto elementy jsou popsány metadaty. Za běhu jsou tyto elementy obsaženy uvnitř domény AppDomain.
Každý z prvků aplikace je vystaven prostřednictvím odpovídajícího typu z oboru názvů System
nebo System.Reflection
.
V okamžiku, kdy máte odkaz na některý z těchto elementů, můžete se pohybovat vztahy mezi daným elementem a souvisejícími prvky, jak je uvedeno na následujícím obrázku.
Třída Type
je nejzákladnějším typem reflexe. Reprezentuje metadata pro jednotlivé deklarace typů v aplikaci. Typy obsahují členy. Ty zahrnují konstruktory, proměnné, vlastnosti, události a metody. Typy mohou navíc obsahovat vnořené typy, které se typicky používají jako pomocné třídy. Typy jsou seskupené do modulů a moduly jsou obsažené v sestavách.
Sestava je logickým ekvivalentem knihovny DLL v systému Win32 a je základní jednotkou zavádění, správy verzí a opakovaného používání typů
Modul je fyzický soubor (.exe, .dll), nebo nějaký prostředek (.gif, .jpg). Sestava může být tvořena několika moduly.
V jádru systému reflexe je System.Type
, což je abstraktní bázová třída poskytující přístup k metadatům nějakého typu.
K instanci třídy Type lze přistoupit pomocí GetType()
. Tato metoda je implementovaná v System.Object
. Po zavolání vrátí metoda konkrétní typ System.Type
, který dokáže typ reflektovat a manipulovat s ním.
Určitou třídu Type
lze převzít pomocí názvu prostřednictvím statické metody GetType()
ve třídě Type
.
Type t = Type.GetType("System.Int32"); Type t2 = Type.GetType("MyNamespace.MyType", MyAssembly); |
C# nabízí operátor typeof
, který vrací třídu Type
libovolného typu známého během kompilace.
Type t = typeof(System.Int32); |
Rozdíl mezi těmito dvěma přístupy je, že přístup pomocí Type.GetType
se vyhodnocuje za běhu, typeof
se vyhodnocuje v době kompilace.
Máme-li instanci Type
, můžeme přistupovat k metadatům prostřednictvím typů, jež představují členy, moduly, sestavy, třídy AppDomain a vnořené typy. lze zkoumat metadata, vlastní atributy, vytvářet nové instance typů a volat členy.
Příklad používá reflexi k zobrazení členů ve třech různých typech.
using System; using System.Reflection; class Test { static void Main() { object o = new Object(); Information(o.GetType()); Information(typeof(int)); Information(Type.GetType("System.String")); } static void Information(Type t) { Console.WriteLine("Type: {0}", t); MemberInfo[] miarr = t.GetMembers(); foreach(MemberInfo mi in miarr) Console.WriteLine(" {0}={1}", mi.MemberType, mi); } } |
Je dynamické vytváření instancí a používání typů za běhu.
//Hello.cs public abstract class Hello { public abstrakt void SayHello(); } |
//EnglishHello.cs using System; public class AmericanHello : Hello { private string message = "Hey Dude!"; public override void SayHello() { Console.WriteLine(message); } } public class BritishHello : Pozdravy { private string message = "Hello!"; public override void SayHello() { Console.WriteLine(message); } } |
//SayHello.cs using System; using System.Reflection; class Test { static void Main() { string s = "EnglishHello.dll"; Assembly a = Assembly.LoadFrom(s); foreach (Type t in a.getTypes()) { if (t.IsSubClasOf(typeof(Hello)) { object o = Activator.CreateInstance(t); MethodInfo mi = t.GetMethod("SayHello"); mi.Invoke(o, null); } } } } |
Podle řetězce s se nahraje EnglishHello.dll. Z jejich typů se vyhledá ten objekt, který má za předka třídu Hello
a zajistí se nalezení metody SayHello
. Metoda se vyvolá.
Obor názvů System.Reflection.Emit
obsahuje třídy, které dokáží vytvořit za běhu úplně nové typy. Třídy umožňují:
definovat dynamickou sestavu v paměti;
definovat dynamický modul v této sestavě;
definovat nový typ v tomto modulu, včetně všech jeho členů;
vytvořit kódy MSIL potřebné k implementování aplikační logiky ve členech.