Skip to content

Instantly share code, notes, and snippets.

@einarwh
Created February 28, 2013 08:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save einarwh/5055242 to your computer and use it in GitHub Desktop.
Save einarwh/5055242 to your computer and use it in GitHub Desktop.
BoxTypeFactory class.
class BoxTypeFactory
{
private readonly Type _type;
private readonly TypeBuilder _boxBuilder;
private readonly FieldInfo _field;
private readonly Dictionary<string, MethodBuilder> _specials = new Dictionary<string, MethodBuilder>();
public BoxTypeFactory(Type type, TypeBuilder boxBuilder, FieldInfo field)
{
_type = type;
_boxBuilder = boxBuilder;
_field = field;
}
public Type Create()
{
foreach (MethodInfo m in _type.GetMethods())
{
if (!IsGetType(m)) CreateProxyMethod(m);
}
foreach (PropertyInfo p in _type.GetProperties())
{
ConnectPropertyToAccessors(p);
}
return _boxBuilder.CreateType();
}
private static bool IsGetType(MethodInfo m)
{
return m.Name == "GetType" && m.GetParameters().Length == 0;
}
private void CreateProxyMethod(MethodInfo m)
{
var parameters = m.GetParameters();
// Create a builder for the current method.
var methodBuilder = _boxBuilder.DefineMethod(m.Name,
MethodAttributes.Public | MethodAttributes.Virtual,
m.ReturnType,
parameters.Select(p => p.ParameterType).ToArray());
var gen = methodBuilder.GetILGenerator();
// Emit opcodes for the method implementation.
// The method should just delegate to the T instance held by the _ field.
gen.Emit(OpCodes.Ldarg_0); // Load 'this' reference onto the stack.
gen.Emit(OpCodes.Ldfld, _field); // Load 'T' reference onto the stack (popping 'this').
for (int i = 1; i < parameters.Length + 1; i++)
{
gen.Emit(OpCodes.Ldarg, i); // Load any method parameters onto the stack.
}
gen.Emit(m.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, m); // Call the method.
gen.Emit(OpCodes.Ret); // Return from method.
// Keep reference to "special" methods (for wiring up properties later).
if (m.IsSpecialName)
{
_specials[m.Name] = methodBuilder;
}
}
private void ConnectPropertyToAccessors(PropertyInfo p)
{
var paramTypes = p.GetIndexParameters().Select(ip => ip.ParameterType).ToArray();
var pb = _boxBuilder.DefineProperty(p.Name, p.Attributes, p.PropertyType, paramTypes);
WireUpIfExists("get_" + p.Name, pb.SetGetMethod);
WireUpIfExists("set_" + p.Name, pb.SetSetMethod);
}
private void WireUpIfExists(string accessor, Action<MethodBuilder> wireUp)
{
if (_specials.ContainsKey(accessor))
{
wireUp(_specials[accessor]);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment