Klasa assembly pozwala na odczytywanie metadanych z różnych assemblies a także ładowanie ich.
var current = Assembly.GetExecutingAssembly(); Console.WriteLine("Current assembly: " + current.FullName); var fromGac = Assembly.Load("System.Xml.Linq,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089"); var restSharpAssembly = Assembly.LoadFrom("RestSharp.dll"); Console.WriteLine("\nLoaded assembly: " + restSharpAssembly.FullName); var dependant = restSharpAssembly.GetReferencedAssemblies(); Console.WriteLine("\nReferenced assemblies:"); foreach (var assemblyName in dependant) Console.WriteLine("\t" + assemblyName.FullName);
Metoda GetExecutingAssembly zwróci nam informacje o assembly, w którym ją wywołujemy (np. plik exe). Za pomocą metody Load możemy ładować assemblies z Global Assembly Cache, podając full name. Z kolei dla assemblies bez strong name możemy użyć metody LoadFrom lub LoadFile szukających na dysku. Jeżeli interesują nas zależne assemblies, możemy uzyskać do nich dostęp przy użyciu metody GetReferencedAssemblies.
Mając obiekt typu Assembly możemy pobrać wszystkie publiczne typy w nim zdefiniowane - służy do tego metoda GetExportedTypes..
Console.WriteLine("\nPublic types:"); var types = restSharpAssembly.GetExportedTypes(); foreach (Type type in types) Console.WriteLine("\t" + type); var stype = (from type in types orderby type.GetCustomAttributes(true).Count() descending select type).First(); var instance = Activator.CreateInstance(stype); Console.WriteLine("\nCreated type instance:" + stype.FullName); var props = stype.GetProperties(); Console.WriteLine("Properties:"); foreach (var propertyInfo in props) Console.WriteLine("\t" + propertyInfo.Name); var tfields = (from type in types let fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic) orderby fields.Count() descending select fields).First(); foreach (var fieldInfo in tfields) Console.WriteLine("\t" + fieldInfo.Name);
Na każdym z typów możemy sprawdzić, jakie zdefiniowano atrybuty (GetCustomAttributes), a także pobrać wszystkie properties (GetProperties) czy pola (GetFields), także te prywatne, ustawiając odpowiednie flagi. Klasa Activator pozwala nam na tworzenie instancji dowolnego typu (rzutowanej do object). Mając taką instancję możemy pobrać MethodInfo i wywołać taką metodę przekazując do niej parametry.
var sw = new Stopwatch(); sw.Start(); var jsonArray = new JsonArray(); for (int i = 0; i < 1000000; i++) { jsonArray.Add(i); } Console.WriteLine("Invoking instance method: {0} ms", sw.ElapsedMilliseconds); sw.Restart(); var methodInfo = stype.GetMethod("Add"); for (int i = 0; i < 1000000; i++) { methodInfo.Invoke(instance, new object[] {i}); } Console.WriteLine("Invoking method via reflection: {0} ms", sw.ElapsedMilliseconds); sw.Reset();
Porównanie takie wypada zdecydowanie na niekorzyść Reflection, głównie przez iterowanie po metadanych i boxing parametrów wejściowych.
Invoking instance method: 83 ms Invoking method via reflection: 2241 ms