Reflection
- Convert List<T> - DataTable using reflection
- GenericComparer<T> using reflection
- Copy or compare properties with reflection.
- Enum description
- EntityFiller: ADO DataReader to entities with reflection
- Static reflection: using .Net 3.5 expressions
Assemblies
The Assembly.GetExecutingAssembly() static method is the most useful.
Assembly.GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false) (returns array)
Getting types
Type[] ts = Assembly.GetExecutingAssembly().GetTypes(); //all types
Type t = this.GetType(); //from an instance
t = typeof(Class1); //from a class name
Type has .IsClass/IsEnum etc, and methods for GetConstructors / Properties / Methods etc (all members inherit MemberInfo).
Use BindingFlags if not just public - eg BindingFlags.Public | BindingFlags.NonPublic (others: IgnoreCase, Static/ Instance)
Find variables (type only, not name) in a method: MethodInfo.GetMethodBody().LocalVariables
object o = Request;
string propName = "Path";
System.Reflection.PropertyInfo prop = o.GetType().GetProperty(propName);
Button1.Text = prop.GetValue(o, null).ToString();
//Button1.Text = Request.Path;
Set Private Fields
Setting private fields (useful in testing if you're not using the MsTest Accessors)
var field = typeof(Category).GetField("_key", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
field.SetValue(_category, "Different");
Dynamic loading
Assembly.LoadFrom(path) or Assembly.Load(qualified name)
Assembly a = Assembly.LoadFrom(@"C:\ClassLibrary.dll"); //load
Type t = a.GetType("ClassLibrary.Class1"); //get type
//find out about it
MethodInfo mi = t.GetMethod("Execute"); //find method
PropertyInfo pi = t.GetProperty("MyProperty"); //find prop
//run it
Object myClass = Activator.CreateInstance(t);
mi.Invoke(myClass, new object[] { 10 }); //call method
int result = (int)pi.GetValue(myClass, null); //call property (GetValue ==Invoke)
NB: Default ctors can be created by Assembly.CreateInstance(string typename), or by System.Activator.CreateInstance(type), or by GetConstructor(Type.EmptyArray).Invoke.
//non default ctor
Type[] arg = new Type[] { typeof(string), typeof(int) };
ConstructorInfo ci = t.GetConstructor(arg); //find default ctor
Object myClass2 = ci.Invoke(new object[] { "Hello", 20 });//pass in empty obj array
Alternative to MemberInfo.Invoke: Type.InvokeMember()
Type t = Type.GetType("Library.Class1, Library"); //get type
Object myClass = Activator.CreateInstance(t);
object result = t.InvokeMember("Execute", BindingFlags.Default | BindingFlags.InvokeMethod,
null, myClass, new object[] {});
Assert.IsTrue((bool)result);
Late Binding
Late bind from a config file (assuming all types have a common interface- useful pattern for injecting mocks just by changing the config xml).
string className = "Library.Class1, Library";
Type t = Type.GetType(className);
ICommand obj = (ICommand)Activator.CreateInstance(t);
obj.Execute();
Down-casting / Cloning
Casting from a base class down to a derived class isn't permitted. So here EntityDerived has a constructor which takes the base class and copies the properties. (Capture the debug.writes for a non-reflected version.) You could also use this for cloning (equivalent to the shallow copy of Object.MemberwiseClone()). See also Copy properties between different objects.
public EntityDerived(EntityBase eb)
{
//copy all properties from base class up to this derived class
PropertyInfo[] allProps = eb.GetType().GetProperties();
foreach (PropertyInfo prop in allProps)
{
if (!prop.CanWrite) continue;
PropertyInfo property = GetType().GetProperty(prop.Name);
Debug.WriteLine(prop.Name + " = eb." + prop.Name + ";");
property.SetValue(this, prop.GetValue(eb, null), null);
}
}
Reflection.Emit
AssemblyName an = new AssemblyName();
an.Name = "MyNewAssembly";
System.Reflection.Emit.AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly
(an, System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave);
ab.Save("newAssembly.dll"); //can't specify path
Then create a ModuleBuilder and DefineType(name, TypeAttributes.Class | TypeAttributes.Public) and so on for MethodBuilder etc... until you get down to the ILGenerator.