Simple .Net Reflection Utility Class
I find that at least once in a project, I am digging into the System.Reflection msdn help page trying to identify what method calls and BindingFlags I need to make to lookup a field, property or method on an object and invoke it. The last time I did this; I took the code and moved it into a class.
Another advantage that I found of using the Reflector class is that it makes my code a little more more readable. It is immediately obvious that
Reflector.StaticGetProperty(typeof(Cusomter), "FullName")
is retrieveing the value of the static property FullName on the Customer type. Compare this to
typeof(Customer).InvokeMember("FullName", BindingFlags.Public | BindingFlags.Static | BindingFlags.GetProperty, null, null, null)
and to a lesser extent
typeof(Cusomter).GetProperty("FullName", BindingFlags.Public | BindingFlags.Static)
Here is the sample usage and below that the utility class …
class Program { static void Main(string[] args) { object matt = Reflector.CreateInstance(typeof(Person), "Matt", "Berseth"); // Print the property values Console.WriteLine(Reflector.GetProperty(matt, "FirstName")); Console.WriteLine(Reflector.GetProperty(matt, "LastName")); // Print the field values Console.WriteLine(Reflector.GetField(matt, "_firstName")); Console.WriteLine(Reflector.GetField(matt, "_lastName")); // Set the property value Reflector.SetProperty(matt, "FirstName", "New First Name"); Console.WriteLine(Reflector.GetProperty(matt, "FirstName")); // Invoke a method Console.WriteLine(Reflector.CallMethod(matt, "FullName")); } } /// <summary> /// /// </summary> public class Person { /// <summary> /// /// </summary> private string _firstName; /// <summary> /// /// </summary> private string _lastName; /// <summary> /// /// </summary> /// <param name="firstName"></param> /// <param name="lastName"></param> public Person(string firstName, string lastName) { this._firstName = firstName; this._lastName = lastName; } /// <summary> /// /// </summary> public string FirstName { get { return this._firstName; } set { this._firstName = value; } } /// <summary> /// /// </summary> public string LastName { get { return this._lastName; } set { this._lastName = value; } } /// <summary> /// /// </summary> /// <returns></returns> public virtual string FullName() { return string.Format("{0} {1}", this.FirstName, this.LastName); } } |
using System; using System.Collections.Generic; using System.Reflection; using System.Text; namespace ReflectionFacade { /// <summary> /// Utility class for easy access to common System.Reflection features /// </summary> public static class Reflector { private const BindingFlags CommonFlags = BindingFlags.Public | BindingFlags.NonPublic; /// <summary> /// /// </summary> public static object CreateInstance(Type type, params object[] args) { return Reflector.InvokeMember( type, null, null, Reflector.CommonFlags | BindingFlags.CreateInstance | BindingFlags.Instance, args); } /// <summary> /// /// </summary> public static void SetField(object target, string fieldName, object value) { Reflector.InvokeMember( target.GetType(), target, fieldName, Reflector.CommonFlags | BindingFlags.SetField | BindingFlags.Instance, value); } /// <summary> /// /// </summary> public static object GetField(object target, string fieldName) { return Reflector.InvokeMember( target.GetType(), target, fieldName, Reflector.CommonFlags | BindingFlags.GetField | BindingFlags.Instance); } /// <summary> /// /// </summary> public static void SetProperty(object target, string propertyName, object value) { Reflector.InvokeMember( target.GetType(), target, propertyName, Reflector.CommonFlags | BindingFlags.SetProperty | BindingFlags.Instance, value); } /// <summary> /// /// </summary> public static object GetProperty(object target, string propertyName) { return Reflector.InvokeMember( target.GetType(), target, propertyName, Reflector.CommonFlags | BindingFlags.GetProperty | BindingFlags.Instance); } /// <summary> /// /// </summary> public static void StaticSetField(Type type, string fieldName, object value) { Reflector.InvokeMember( type, null, fieldName, Reflector.CommonFlags | BindingFlags.SetField | BindingFlags.Static, value); } /// <summary> /// /// </summary> public static object StaticGetField(Type type, string fieldName) { return Reflector.InvokeMember( type, null, fieldName, Reflector.CommonFlags | BindingFlags.GetField | BindingFlags.Static); } /// <summary> /// /// </summary> public static void StaticSetProperty(Type type, string propertyName, object value) { Reflector.InvokeMember( type, null, propertyName, Reflector.CommonFlags | BindingFlags.SetProperty | BindingFlags.Static, value); } /// <summary> /// /// </summary> public static object StaticGetProperty(Type type, string propertyName) { return Reflector.InvokeMember( type, null, propertyName, Reflector.CommonFlags | BindingFlags.GetProperty | BindingFlags.Static); } /// <summary> /// /// </summary> public static object CallMethod(object target, string methodName, params object[] args) { return Reflector.InvokeMember( target.GetType(), target, methodName, Reflector.CommonFlags | BindingFlags.InvokeMethod | BindingFlags.Instance, args); } /// <summary> /// /// </summary> public static object StaticCallMethod(Type type, string memberName, params object[] args) { return Reflector.InvokeMember( type, null, null, Reflector.CommonFlags | BindingFlags.InvokeMethod | BindingFlags.Static, args); } /// <summary> /// /// </summary> private static object InvokeMember( Type type, object target, string memberName, BindingFlags flags, params object[] args) { return type.InvokeMember(memberName, flags, null, target, args); } } } |
Comments
you should be very careful with reflection. Performance of GetProperty and GetMethod methods is really poor. I would recomend to precache memberName to PropertyInfo (MethodInfo) pairs in dictionary.
You are right on Max. For completeness, I will post a follow-up comparing the relative performance of this utility class versus, caching, versus invoking the members directly.
I believe including BindingFlags.Public in the flags for any reflection call is redundant.