using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace Dynamic
{
/// <summary>
/// Represents a virtual assembly in memory
/// </summary>
public class Namespace : IDisposable
{
private readonly AssemblyName _assemblyName;
private readonly AssemblyBuilder _assemblyBuilder;
private readonly ModuleBuilder _moduleBuilder;
private readonly List<Type> _classes = new List<Type>();
/// <summary>
/// A collection of classes belonging to this dynamic namespace
/// </summary>
public Type[] Classes { get { return _classes.ToArray(); } }
private readonly List<Type> _interfaces = new List<Type>();
/// <summary>
/// A collection of interfaces belonging to this dynamic namespace
/// </summary>
public Type[] Interfaces { get { return _interfaces.ToArray(); } }
private readonly List<Type> _enums = new List<Type>();
/// <summary>
/// A collection of enums belonging to this dynamic namespace
/// </summary>
public Type[] Enums { get { return _enums.ToArray(); } }
/// <summary>
/// Creates a new dynamic namespace for containing simple dynamic types
/// </summary>
public Namespace()
{
_assemblyName = new AssemblyName(Guid.NewGuid().ToString());
// Assembly builder MUST be set to run and collect to be disposable. The dynamic assembly will participate in normal garbage collection when all references to it and its types are released.
// REF: http://msdn.microsoft.com/en-us/library/dd554932.aspx
_assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(_assemblyName, AssemblyBuilderAccess.RunAndCollect);
_moduleBuilder = _assemblyBuilder.DefineDynamicModule(_assemblyName.Name, _assemblyName.Name + ".dll");
}
/// <summary>
/// Creates a dynamic type that lives in this dynamic namespace
/// </summary>
/// <param name="name">The name of the dynamic type</param>
/// <param name="properties">A collection of auto-properties the dynamic type will have</param>
/// <param name="fields">A collection of read/write fields the dynamic type will have</param>
/// <param name="baseType">Optional base type for this dynamic type to inherit from</param>
/// <param name="ifaces">Optional interfaces this dynamic type implements</param>
/// <param name="attrs">Optional interfaces this dynamic type implements</param>
/// <returns>The created dynamic type</returns>
public Type CreateClass(string name, Property[] properties, Property[] fields, Type baseType = null, Type[] ifaces = null, Attribute[] attrs = null)
{
baseType = baseType ?? typeof(object);
// Define Type
var builder = _moduleBuilder.DefineType(name, TypeAttributes.Public, baseType, ifaces);
// ImplementInterfaces
(ifaces ?? new Type[0]).ToList().ForEach(builder.AddInterfaceImplementation);
// Define Attributes
(attrs ?? new Attribute[0]).ToList().ForEach(a => builder.SetCustomAttribute(GetAttributeBuilder(a)));
// Define Properties
(properties ?? new Property[0]).ToList().ForEach(p => GetAutoPropertyBuilder(builder, p, ifaces));
// Define Fields
(fields ?? new Property[0]).ToList().ForEach(f => builder.DefineField(f.Name, f.Type, FieldAttributes.Public));
// Forwarding all constructors
var baseCtors = baseType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var baseCtor in baseCtors)
{
// Getting parameter information
var parms = baseCtor.GetParameters();
var parmTypes = parms.Select(p => p.ParameterType).ToArray();
var reqModifiers = parms.Select(p => p.GetRequiredCustomModifiers()).ToArray();
var optModifiers = parms.Select(p => p.GetOptionalCustomModifiers()).ToArray();
if (parms.Length > 0 && parms.Last().IsDefined(typeof(ParamArrayAttribute), false)) { continue; }
var ctor = builder.DefineConstructor(MethodAttributes.Public, baseCtor.CallingConvention, parmTypes, reqModifiers, optModifiers);
// Adding parameters
for (var i = 0; i < parms.Length; i++)
{
var parm = ctor.DefineParameter(i + 1, parms[i].Attributes, parms[i].Name);
if (((int)parms[i].Attributes & (int)ParameterAttributes.HasDefault) != 0)
{
parm.SetConstant(parms[i].RawDefaultValue);
}
parms[i].DynamicAttributes()
.ToList()
.ForEach(a => parm.SetCustomAttribute(GetAttributeBuilder(a)));
}
// Setting attributes
baseCtor.DynamicAttributes()
.ToList()
.ForEach(a => ctor.SetCustomAttribute(GetAttributeBuilder(a)));
// Forwarding parameters to baseCtor
var il = ctor.GetILGenerator();
il.Emit(OpCodes.Nop);
// Loading args
il.Emit(OpCodes.Ldarg_0); // 'this'
for (var i = 1; i <= parms.Length; i++)
il.Emit(OpCodes.Ldarg, i); // param i
// Calling baseCtor with loaded args
il.Emit(OpCodes.Call, baseCtor);
il.Emit(OpCodes.Ret);
}
_classes.Add(builder.CreateType()); // Generate Type and return
return _classes.Last();
}
/// <summary>
/// Creates an dynamic enum type that lives in this dynamic namespace
/// </summary>
/// <typeparam name="TBase">The underlying value type for this enumeration</typeparam>
/// <param name="name">The name of this dynamic enum</param>
/// <param name="values">A collection of names/values this dynamic enum will have</param>
/// <returns>The created dynamic enum</returns>
public Type CreateEnum<TBase>(string name, IDictionary<string, TBase> values)
{
var builder = _moduleBuilder.DefineEnum(name, TypeAttributes.Public, typeof(TBase));
// Create literals
foreach (var value in values)
{
builder.DefineLiteral(value.Key, value.Value);
}
_enums.Add(builder.CreateType());
return _enums.Last();
}
/// <summary>
/// Creates an dynamic interface type that lives in this dynamic namespace
/// </summary>
/// <param name="name">The name of this dynamic interface</param>
/// <param name="properties">The property signatures for this dynamic interface</param>
/// <param name="methods">The method signatures for this dynamic interface</param>
/// <param name="ifaces">Optional interfaces this dynamic interface implements</param>
/// <returns>The dynamic interface</returns>
public Type CreateInterface(string name, Property[] properties, Method[] methods, Type[] ifaces = null, Attribute[] attrs = null)
{
// Define Type
var builder = _moduleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract, null, ifaces);
// Define Attributes
(attrs ?? new Attribute[0]).ToList().ForEach(a => builder.SetCustomAttribute(GetAttributeBuilder(a)));
// Define Properties
var propertyAttrs = MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | MethodAttributes.VtableLayoutMask | MethodAttributes.SpecialName;
foreach (var property in properties ?? new Property[0])
{
var pbuild = GetPropertyBuilder(builder, property);
pbuild.SetGetMethod(builder.DefineMethod("get_" + property.Name, propertyAttrs, property.Type, Type.EmptyTypes));
pbuild.SetSetMethod(builder.DefineMethod("set_" + property.Name, propertyAttrs, typeof(void), new[] { property.Type }));
}
(properties ?? new Property[0]).ToList().ForEach(p => GetPropertyBuilder(builder, p));
// Define Methods
foreach (var method in methods ?? new Method[0])
{
var methBuilder = builder.DefineMethod(
method.MethodName, MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual,
method.ReturnType, method.Parameters.Select(p => p.Type).ToArray());
(method.Attributes ?? new Attribute[0]).ToList().ForEach(a => methBuilder.SetCustomAttribute(GetAttributeBuilder(a)));
for (var i = 0; i < method.Parameters.Length; i++)
{
var parm = method.Parameters[i];
var parmBuilder = methBuilder.DefineParameter(i + 1, ParameterAttributes.None, parm.Name);
(parm.Attributes ?? new Attribute[0]).ToList().ForEach(a => parmBuilder.SetCustomAttribute(GetAttributeBuilder(a)));
}
}
_interfaces.Add(builder.CreateType()); // Generate Type and return
return _interfaces.Last();
}
private CustomAttributeBuilder GetAttributeBuilder(Attribute attribute)
{
if (attribute.Properties.Count > 0 && attribute.Fields.Count > 0)
return new CustomAttributeBuilder(attribute.Constructor, attribute.Parameters,
attribute.Properties.Keys.ToArray(), attribute.Properties.Values.ToArray(),
attribute.Fields.Keys.ToArray(), attribute.Fields.Values.ToArray());
if (attribute.Properties.Count > 0)
return new CustomAttributeBuilder(attribute.Constructor, attribute.Parameters,
attribute.Properties.Keys.ToArray(), attribute.Properties.Values.ToArray());
if (attribute.Fields.Count > 0)
return new CustomAttributeBuilder(attribute.Constructor, attribute.Parameters,
attribute.Fields.Keys.ToArray(), attribute.Fields.Values.ToArray());
return new CustomAttributeBuilder(attribute.Constructor, attribute.Parameters);
}
private PropertyBuilder GetAutoPropertyBuilder(TypeBuilder builder, Property property, Type[] ifaces)
{
var field = builder.DefineField("_" + property.Name.ToLower() + "_field", property.Type, FieldAttributes.Private);
var pbuilder = GetWiredPropertyBuilder(builder, property, ifaces,
get =>
{
get.Emit(OpCodes.Ldarg_0);
get.Emit(OpCodes.Ldfld, field);
get.Emit(OpCodes.Ret);
},
set =>
{
set.Emit(OpCodes.Ldarg_0);
set.Emit(OpCodes.Ldarg_1);
set.Emit(OpCodes.Stfld, field);
set.Emit(OpCodes.Ret);
});
return pbuilder;
}
private PropertyBuilder GetWiredPropertyBuilder(TypeBuilder builder, Property property, Type[] ifaces, Action<ILGenerator> getter, Action<ILGenerator> setter)
{
var prop = GetPropertyBuilder(builder, property);
var iprops = (ifaces ?? new Type[0]).Select(i => i.GetProperty(property.Name)).Where(p => p != null).ToList();
if (getter != null)
{
var igets = iprops.Select(p => p.GetGetMethod()).Where(g => g != null).ToList();
var attr = igets.Count == 0
? MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig
: MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
var get = builder.DefineMethod("get_" + property.Name, attr, property.Type, Type.EmptyTypes);
getter(get.GetILGenerator());
prop.SetGetMethod(get);
igets.ForEach(g => builder.DefineMethodOverride(get, g));
}
if (setter != null)
{
var isets = iprops.Select(p => p.GetSetMethod()).Where(s => s != null).ToList();
var attr = isets.Count == 0
? MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig
: MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
var set = builder.DefineMethod("set_" + property.Name, attr, typeof(void), new[] { property.Type });
setter(set.GetILGenerator());
prop.SetSetMethod(set);
isets.ForEach(s => builder.DefineMethodOverride(set, s));
}
return prop;
}
private PropertyBuilder GetPropertyBuilder(TypeBuilder builder, Property property)
{
var prop = builder.DefineProperty(property.Name, PropertyAttributes.None, property.Type, null);
// Defining Attributes
(property.Attributes ?? new Attribute[0]).ToList().ForEach(a => prop.SetCustomAttribute(GetAttributeBuilder(a)));
return prop;
}
/// <summary>
/// Releases internal references to the dynamic assembly <br />
/// WARNING: The memory consumed by a dynamic assembly and its types will not be released until all references to its types have been released from your code.
/// </summary>
public void Dispose()
{
_classes.Clear();
_enums.Clear();
_interfaces.Clear();
}
public class Method
{
public string MethodName { get; private set; }
public Type ReturnType { get; private set; }
public Parameter[] Parameters { get; private set; }
public Attribute[] Attributes { get; private set; }
public Method(string name, Type ret, Parameter[] parms, Attribute[] attr = null)
{
MethodName = name;
ReturnType = ret;
Parameters = parms;
Attributes = attr;
}
}
public class Parameter
{
public string Name { get; private set; }
public Type Type { get; private set; }
public Attribute[] Attributes { get; private set; }
public Parameter(string name, Type type, Attribute[] attr = null)
{
Name = name;
Type = type;
Attributes = attr;
}
}
public class Property
{
public string Name { get; private set; }
public Type Type { get; private set; }
public Attribute[] Attributes { get; private set; }
public Property(string name, Type type, Attribute[] attr = null)
{
Name = name;
Type = type;
Attributes = attr;
}
}
public class Attribute
{
public Type Type { get; private set; }
public ConstructorInfo Constructor { get; private set; }
public object[] Parameters { get; private set; }
public Dictionary<PropertyInfo, object> Properties { get; private set; }
public Dictionary<FieldInfo, object> Fields { get; private set; }
public Attribute(Type type, ConstructorInfo ctor, object[] parms, IDictionary<PropertyInfo, object> props, IDictionary<FieldInfo, object> fields)
{
Type = type;
Constructor = ctor;
Parameters = parms;
Properties = props.ToDictionary(d => d.Key, d => d.Value);
Fields = fields.ToDictionary(d => d.Key, d => d.Value);
}
}
}
public static class DynamicExtensions
{
public static Namespace.Method[] DynamicMethods(this Type type)
{
return type.GetMethods()
.Select(m => new Namespace.Method(m.Name, m.ReturnType, m.GetParameters()
.Select(p => new Namespace.Parameter(p.Name, p.ParameterType))
.ToArray(), m.DynamicAttributes()))
.ToArray();
}
public static Namespace.Property[] DynamicProperties(this Type type)
{
return type.GetProperties()
.Select(p => new Namespace.Property(p.Name, p.PropertyType))
.ToArray();
}
public static Namespace.Attribute[] DynamicAttributes(this MemberInfo member)
{
return member.GetCustomAttributesData().Select(ConvertAttribute).ToArray();
}
public static Namespace.Attribute[] DynamicAttributes(this ParameterInfo param)
{
return param.GetCustomAttributesData().Select(ConvertAttribute).ToArray();
}
private static Namespace.Attribute ConvertAttribute(CustomAttributeData data)
{
return new Namespace.Attribute(
data.Constructor.DeclaringType, data.Constructor, data.ConstructorArguments.Select(p => (object)p.Value).ToArray(),
(data.NamedArguments ?? new CustomAttributeNamedArgument[0]).Where(p => p.MemberInfo is PropertyInfo).ToDictionary(p => (PropertyInfo)p.MemberInfo, p => p.TypedValue.Value),
(data.NamedArguments ?? new CustomAttributeNamedArgument[0]).Where(p => !(p.MemberInfo is FieldInfo)).ToDictionary(p => (FieldInfo)p.MemberInfo, p => p.TypedValue.Value));
}
}
}
Basically you can just copy/paste this into a single .cs file in your project to try it out and see how it works. This is all System.Reflection.Emit with a small amount of IL in there. Most of this is just knowing how types are structured after being compiled and then just using the Emit builders to put it all together. What I've done here is packaged everything in a "hopefully" easy to understand API that allows you to create very simple class, interface, and enum types with auto-properties and what-not. If this helped you with some project somewhere it would be cool to hear about it. (www.markonthenet.com)
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace Dynamic
{
/// <summary>
/// Represents a virtual assembly in memory
/// </summary>
public class Namespace : IDisposable
{
private readonly AssemblyName _assemblyName;
private readonly AssemblyBuilder _assemblyBuilder;
private readonly ModuleBuilder _moduleBuilder;
private readonly List<Type> _classes = new List<Type>();
/// <summary>
/// A collection of classes belonging to this dynamic namespace
/// </summary>
public Type[] Classes { get { return _classes.ToArray(); } }
private readonly List<Type> _interfaces = new List<Type>();
/// <summary>
/// A collection of interfaces belonging to this dynamic namespace
/// </summary>
public Type[] Interfaces { get { return _interfaces.ToArray(); } }
private readonly List<Type> _enums = new List<Type>();
/// <summary>
/// A collection of enums belonging to this dynamic namespace
/// </summary>
public Type[] Enums { get { return _enums.ToArray(); } }
/// <summary>
/// Creates a new dynamic namespace for containing simple dynamic types
/// </summary>
public Namespace()
{
_assemblyName = new AssemblyName(Guid.NewGuid().ToString());
// Assembly builder MUST be set to run and collect to be disposable. The dynamic assembly will participate in normal garbage collection when all references to it and its types are released.
// REF: http://msdn.microsoft.com/en-us/library/dd554932.aspx
_assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(_assemblyName, AssemblyBuilderAccess.RunAndCollect);
_moduleBuilder = _assemblyBuilder.DefineDynamicModule(_assemblyName.Name, _assemblyName.Name + ".dll");
}
/// <summary>
/// Creates a dynamic type that lives in this dynamic namespace
/// </summary>
/// <param name="name">The name of the dynamic type</param>
/// <param name="properties">A collection of auto-properties the dynamic type will have</param>
/// <param name="fields">A collection of read/write fields the dynamic type will have</param>
/// <param name="baseType">Optional base type for this dynamic type to inherit from</param>
/// <param name="ifaces">Optional interfaces this dynamic type implements</param>
/// <param name="attrs">Optional interfaces this dynamic type implements</param>
/// <returns>The created dynamic type</returns>
public Type CreateClass(string name, Property[] properties, Property[] fields, Type baseType = null, Type[] ifaces = null, Attribute[] attrs = null)
{
baseType = baseType ?? typeof(object);
// Define Type
var builder = _moduleBuilder.DefineType(name, TypeAttributes.Public, baseType, ifaces);
// ImplementInterfaces
(ifaces ?? new Type[0]).ToList().ForEach(builder.AddInterfaceImplementation);
// Define Attributes
(attrs ?? new Attribute[0]).ToList().ForEach(a => builder.SetCustomAttribute(GetAttributeBuilder(a)));
// Define Properties
(properties ?? new Property[0]).ToList().ForEach(p => GetAutoPropertyBuilder(builder, p, ifaces));
// Define Fields
(fields ?? new Property[0]).ToList().ForEach(f => builder.DefineField(f.Name, f.Type, FieldAttributes.Public));
// Forwarding all constructors
var baseCtors = baseType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var baseCtor in baseCtors)
{
// Getting parameter information
var parms = baseCtor.GetParameters();
var parmTypes = parms.Select(p => p.ParameterType).ToArray();
var reqModifiers = parms.Select(p => p.GetRequiredCustomModifiers()).ToArray();
var optModifiers = parms.Select(p => p.GetOptionalCustomModifiers()).ToArray();
if (parms.Length > 0 && parms.Last().IsDefined(typeof(ParamArrayAttribute), false)) { continue; }
var ctor = builder.DefineConstructor(MethodAttributes.Public, baseCtor.CallingConvention, parmTypes, reqModifiers, optModifiers);
// Adding parameters
for (var i = 0; i < parms.Length; i++)
{
var parm = ctor.DefineParameter(i + 1, parms[i].Attributes, parms[i].Name);
if (((int)parms[i].Attributes & (int)ParameterAttributes.HasDefault) != 0)
{
parm.SetConstant(parms[i].RawDefaultValue);
}
parms[i].DynamicAttributes()
.ToList()
.ForEach(a => parm.SetCustomAttribute(GetAttributeBuilder(a)));
}
// Setting attributes
baseCtor.DynamicAttributes()
.ToList()
.ForEach(a => ctor.SetCustomAttribute(GetAttributeBuilder(a)));
// Forwarding parameters to baseCtor
var il = ctor.GetILGenerator();
il.Emit(OpCodes.Nop);
// Loading args
il.Emit(OpCodes.Ldarg_0); // 'this'
for (var i = 1; i <= parms.Length; i++)
il.Emit(OpCodes.Ldarg, i); // param i
// Calling baseCtor with loaded args
il.Emit(OpCodes.Call, baseCtor);
il.Emit(OpCodes.Ret);
}
_classes.Add(builder.CreateType()); // Generate Type and return
return _classes.Last();
}
/// <summary>
/// Creates an dynamic enum type that lives in this dynamic namespace
/// </summary>
/// <typeparam name="TBase">The underlying value type for this enumeration</typeparam>
/// <param name="name">The name of this dynamic enum</param>
/// <param name="values">A collection of names/values this dynamic enum will have</param>
/// <returns>The created dynamic enum</returns>
public Type CreateEnum<TBase>(string name, IDictionary<string, TBase> values)
{
var builder = _moduleBuilder.DefineEnum(name, TypeAttributes.Public, typeof(TBase));
// Create literals
foreach (var value in values)
{
builder.DefineLiteral(value.Key, value.Value);
}
_enums.Add(builder.CreateType());
return _enums.Last();
}
/// <summary>
/// Creates an dynamic interface type that lives in this dynamic namespace
/// </summary>
/// <param name="name">The name of this dynamic interface</param>
/// <param name="properties">The property signatures for this dynamic interface</param>
/// <param name="methods">The method signatures for this dynamic interface</param>
/// <param name="ifaces">Optional interfaces this dynamic interface implements</param>
/// <returns>The dynamic interface</returns>
public Type CreateInterface(string name, Property[] properties, Method[] methods, Type[] ifaces = null, Attribute[] attrs = null)
{
// Define Type
var builder = _moduleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract, null, ifaces);
// Define Attributes
(attrs ?? new Attribute[0]).ToList().ForEach(a => builder.SetCustomAttribute(GetAttributeBuilder(a)));
// Define Properties
var propertyAttrs = MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | MethodAttributes.VtableLayoutMask | MethodAttributes.SpecialName;
foreach (var property in properties ?? new Property[0])
{
var pbuild = GetPropertyBuilder(builder, property);
pbuild.SetGetMethod(builder.DefineMethod("get_" + property.Name, propertyAttrs, property.Type, Type.EmptyTypes));
pbuild.SetSetMethod(builder.DefineMethod("set_" + property.Name, propertyAttrs, typeof(void), new[] { property.Type }));
}
(properties ?? new Property[0]).ToList().ForEach(p => GetPropertyBuilder(builder, p));
// Define Methods
foreach (var method in methods ?? new Method[0])
{
var methBuilder = builder.DefineMethod(
method.MethodName, MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual,
method.ReturnType, method.Parameters.Select(p => p.Type).ToArray());
(method.Attributes ?? new Attribute[0]).ToList().ForEach(a => methBuilder.SetCustomAttribute(GetAttributeBuilder(a)));
for (var i = 0; i < method.Parameters.Length; i++)
{
var parm = method.Parameters[i];
var parmBuilder = methBuilder.DefineParameter(i + 1, ParameterAttributes.None, parm.Name);
(parm.Attributes ?? new Attribute[0]).ToList().ForEach(a => parmBuilder.SetCustomAttribute(GetAttributeBuilder(a)));
}
}
_interfaces.Add(builder.CreateType()); // Generate Type and return
return _interfaces.Last();
}
private CustomAttributeBuilder GetAttributeBuilder(Attribute attribute)
{
if (attribute.Properties.Count > 0 && attribute.Fields.Count > 0)
return new CustomAttributeBuilder(attribute.Constructor, attribute.Parameters,
attribute.Properties.Keys.ToArray(), attribute.Properties.Values.ToArray(),
attribute.Fields.Keys.ToArray(), attribute.Fields.Values.ToArray());
if (attribute.Properties.Count > 0)
return new CustomAttributeBuilder(attribute.Constructor, attribute.Parameters,
attribute.Properties.Keys.ToArray(), attribute.Properties.Values.ToArray());
if (attribute.Fields.Count > 0)
return new CustomAttributeBuilder(attribute.Constructor, attribute.Parameters,
attribute.Fields.Keys.ToArray(), attribute.Fields.Values.ToArray());
return new CustomAttributeBuilder(attribute.Constructor, attribute.Parameters);
}
private PropertyBuilder GetAutoPropertyBuilder(TypeBuilder builder, Property property, Type[] ifaces)
{
var field = builder.DefineField("_" + property.Name.ToLower() + "_field", property.Type, FieldAttributes.Private);
var pbuilder = GetWiredPropertyBuilder(builder, property, ifaces,
get =>
{
get.Emit(OpCodes.Ldarg_0);
get.Emit(OpCodes.Ldfld, field);
get.Emit(OpCodes.Ret);
},
set =>
{
set.Emit(OpCodes.Ldarg_0);
set.Emit(OpCodes.Ldarg_1);
set.Emit(OpCodes.Stfld, field);
set.Emit(OpCodes.Ret);
});
return pbuilder;
}
private PropertyBuilder GetWiredPropertyBuilder(TypeBuilder builder, Property property, Type[] ifaces, Action<ILGenerator> getter, Action<ILGenerator> setter)
{
var prop = GetPropertyBuilder(builder, property);
var iprops = (ifaces ?? new Type[0]).Select(i => i.GetProperty(property.Name)).Where(p => p != null).ToList();
if (getter != null)
{
var igets = iprops.Select(p => p.GetGetMethod()).Where(g => g != null).ToList();
var attr = igets.Count == 0
? MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig
: MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
var get = builder.DefineMethod("get_" + property.Name, attr, property.Type, Type.EmptyTypes);
getter(get.GetILGenerator());
prop.SetGetMethod(get);
igets.ForEach(g => builder.DefineMethodOverride(get, g));
}
if (setter != null)
{
var isets = iprops.Select(p => p.GetSetMethod()).Where(s => s != null).ToList();
var attr = isets.Count == 0
? MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig
: MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
var set = builder.DefineMethod("set_" + property.Name, attr, typeof(void), new[] { property.Type });
setter(set.GetILGenerator());
prop.SetSetMethod(set);
isets.ForEach(s => builder.DefineMethodOverride(set, s));
}
return prop;
}
private PropertyBuilder GetPropertyBuilder(TypeBuilder builder, Property property)
{
var prop = builder.DefineProperty(property.Name, PropertyAttributes.None, property.Type, null);
// Defining Attributes
(property.Attributes ?? new Attribute[0]).ToList().ForEach(a => prop.SetCustomAttribute(GetAttributeBuilder(a)));
return prop;
}
/// <summary>
/// Releases internal references to the dynamic assembly <br />
/// WARNING: The memory consumed by a dynamic assembly and its types will not be released until all references to its types have been released from your code.
/// </summary>
public void Dispose()
{
_classes.Clear();
_enums.Clear();
_interfaces.Clear();
}
public class Method
{
public string MethodName { get; private set; }
public Type ReturnType { get; private set; }
public Parameter[] Parameters { get; private set; }
public Attribute[] Attributes { get; private set; }
public Method(string name, Type ret, Parameter[] parms, Attribute[] attr = null)
{
MethodName = name;
ReturnType = ret;
Parameters = parms;
Attributes = attr;
}
}
public class Parameter
{
public string Name { get; private set; }
public Type Type { get; private set; }
public Attribute[] Attributes { get; private set; }
public Parameter(string name, Type type, Attribute[] attr = null)
{
Name = name;
Type = type;
Attributes = attr;
}
}
public class Property
{
public string Name { get; private set; }
public Type Type { get; private set; }
public Attribute[] Attributes { get; private set; }
public Property(string name, Type type, Attribute[] attr = null)
{
Name = name;
Type = type;
Attributes = attr;
}
}
public class Attribute
{
public Type Type { get; private set; }
public ConstructorInfo Constructor { get; private set; }
public object[] Parameters { get; private set; }
public Dictionary<PropertyInfo, object> Properties { get; private set; }
public Dictionary<FieldInfo, object> Fields { get; private set; }
public Attribute(Type type, ConstructorInfo ctor, object[] parms, IDictionary<PropertyInfo, object> props, IDictionary<FieldInfo, object> fields)
{
Type = type;
Constructor = ctor;
Parameters = parms;
Properties = props.ToDictionary(d => d.Key, d => d.Value);
Fields = fields.ToDictionary(d => d.Key, d => d.Value);
}
}
}
public static class DynamicExtensions
{
public static Namespace.Method[] DynamicMethods(this Type type)
{
return type.GetMethods()
.Select(m => new Namespace.Method(m.Name, m.ReturnType, m.GetParameters()
.Select(p => new Namespace.Parameter(p.Name, p.ParameterType))
.ToArray(), m.DynamicAttributes()))
.ToArray();
}
public static Namespace.Property[] DynamicProperties(this Type type)
{
return type.GetProperties()
.Select(p => new Namespace.Property(p.Name, p.PropertyType))
.ToArray();
}
public static Namespace.Attribute[] DynamicAttributes(this MemberInfo member)
{
return member.GetCustomAttributesData().Select(ConvertAttribute).ToArray();
}
public static Namespace.Attribute[] DynamicAttributes(this ParameterInfo param)
{
return param.GetCustomAttributesData().Select(ConvertAttribute).ToArray();
}
private static Namespace.Attribute ConvertAttribute(CustomAttributeData data)
{
return new Namespace.Attribute(
data.Constructor.DeclaringType, data.Constructor, data.ConstructorArguments.Select(p => (object)p.Value).ToArray(),
(data.NamedArguments ?? new CustomAttributeNamedArgument[0]).Where(p => p.MemberInfo is PropertyInfo).ToDictionary(p => (PropertyInfo)p.MemberInfo, p => p.TypedValue.Value),
(data.NamedArguments ?? new CustomAttributeNamedArgument[0]).Where(p => !(p.MemberInfo is FieldInfo)).ToDictionary(p => (FieldInfo)p.MemberInfo, p => p.TypedValue.Value));
}
}
}