Mit Reflection kann man Klassen, Typen, Methoden, … von außen betrachten und benutzen. So erlaubt Reflection eine Instanz einer Klasse zu erstellen und darauf Methoden aufzurufen, die zur Compile-Zeit noch nicht bekannt sind. Außerdem ist es so möglich den Inhalt einer DLL (Klassen, Methoden, …) aufzulisten ohne den Quellcode zu kennen.
Wie komme ich an Informationen eines bekannten Typs? Antwort: typeof(…)
Wie kann ich den Inhalt einer DLL erfassen? Antwort: Assembly.LoadFrom(…)
In den folgenden Teilabschnitten sind Beispiele (Code-Snipsets) zu sehen, die Zeigen, wie mit Reflection gearbeitet werden kann:
Werte kopieren mit Reflection
public static void CopyValues<a,b>(A from, B to) { Type aType = typeof(A); Type bType = typeof(B); var aProperties = aType.GetProperties().Where(x => x.CanRead); var bProperties = bType.GetProperties().Where(x => x.CanWrite); foreach (var aProperty in aProperties) { // Search for equivalent b-Property: var bProperty = bProperties.FirstOrDefault(x => x.Name == aProperty.Name && x.MemberType == aProperty.MemberType); if (bProperty != null) { bProperty.SetValue(to, aProperty.GetValue(from)); } } }
Wie hier zu erkennen ist, werden über die beiden generischen Parameter die Typ-Informationen ausgelesen um danach zu ermitteln, welche Properties vorhanden sind. Bei dem From-Objekt brauchen wir nur lesenden Zugriff auf die Properties und beim To-Objekt nur schreibenden.
Methode aufrufen mit Hilfe eines Strings
public static void CallMethod(object source, string method) { if(source!=null) { Type typeInfo = source.GetType(); MethodInfo toCall= typeInfo.GetMethod(method); toCall.Invoke(source, null); } }
Mit Invoke wird die eigentliche Methode aufgerufen. Der erste Parameter bestimmt das Objekt und der zweite die Werte für die Parameter der Methode.
Objekte erzeugen
Konstruktoren werden genauso wie Methoden aufgerufen.
Type myType = typeof(A); ConstructorInfo myConstructor=myType.GetConstructor(Type.EmptyTypes); object myObject=myConstructor.Invoke(null);
String Search für Objekte
public static IEnumerable<object> SearchStringInObjects(this IEnumerable<object> source, string toSearch) { if (source.Any()) { foreach (var item in source) { Type typeOfItem = item.GetType(); foreach (var property in typeOfItem.GetProperties().Where(x => x.CanRead)) { var valueOfProperty = property.GetValue(item); if (valueOfProperty != null && valueOfProperty.ToString().Contains(toSearch)) { yield return item; } } } } }
In diesem Beispiel wird eine Erweiterungsmethode geschrieben die aus einer Aufzählung alle die Objekte rausfiltert, die ein Property besitzen, das den übergebenen String enthält.
Assembly auslesen
static string ReadAssembly(string filename) { StringBuilder toReturn = new StringBuilder(); Assembly data = Assembly.LoadFile(filename); toReturn.AppendLine("Name of Assembly: " + data.FullName); toReturn.AppendLine("Included Types: "); foreach (var item in data.GetTypes()) { toReturn.AppendLine(" " + item.FullName); foreach (MethodInfo method in item.GetMethods()) { toReturn.AppendLine(" Method: " + method.Name); } foreach (PropertyInfo property in item.GetProperties()) { toReturn.AppendLine(" Property: " + property.Name); } } return toReturn.ToString(); }
Wie hier zu erkennen ist, wird ein Assembly Objekt angelegt. Über dieses Objekt ist der gesamte Inhalt der Assembly abrufbar.