Skip to content

Instantly share code, notes, and snippets.

@kkozmic
Created October 11, 2009 08:30
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 kkozmic/207542 to your computer and use it in GitHub Desktop.
Save kkozmic/207542 to your computer and use it in GitHub Desktop.
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace DP115Test
{
using System;
class Program
{
static void Main(string[] args)
{
var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Foo"), AssemblyBuilderAccess.RunAndSave);
var type = assembly
.DefineDynamicModule("FooModule", "FooModule.dll", true)
.DefineType("AClass", TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit, typeof(object), new[] { typeof(IFoo) });
var method = type.DefineMethod("IFoo.SomeMethod", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, CallingConventions.HasThis);
var typeParameters = method.DefineGenericParameters(new[] { "TBase", "TInherited" });
typeParameters[1].SetBaseTypeConstraint(typeParameters[0]);
type.DefineMethodOverride(method, typeof(IFoo).GetMethods().Single());
ConstructorBuilder nestedCtor;
MethodBuilder nestedMethod;
TypeBuilder nested = GenerateInvocationType(type, method, out nestedCtor, out nestedMethod);
GenerateSomeMethod(method, nested, typeParameters, nestedCtor, nestedMethod);
var createdType = type.CreateType();
nested.CreateType();
assembly.Save("FooModule.dll");
var instance = Activator.CreateInstance(createdType) as IFoo;
//instance.SomeMethod<IComparable<string>, string>(); // NOTE: will currently yield StackOverflowException
}
private static TypeBuilder GenerateInvocationType(TypeBuilder type, MethodBuilder method, out ConstructorBuilder nestedCtor, out MethodBuilder nestedMethod)
{
var builder = type.DefineNestedType("NestedClass",
TypeAttributes.AutoLayout | TypeAttributes.AnsiClass |
TypeAttributes.Serializable |
TypeAttributes.Sealed | TypeAttributes.NestedAssembly, typeof (object),
new[] {typeof (IInvocation)});
var typeParameters = builder.DefineGenericParameters(new[] {"TBase_NestedType", "TInherited_NestedType"});
typeParameters[1].SetBaseTypeConstraint(typeParameters[0]);
var target = builder.DefineField("target", type, FieldAttributes.InitOnly | FieldAttributes.Private);
nestedCtor = GenerateCtor(type, builder, target);
nestedMethod = GenerateInvokeOnTarget(type, builder, target, typeParameters, method);
return builder;
}
private static MethodBuilder GenerateInvokeOnTarget(TypeBuilder type, TypeBuilder builder, FieldBuilder target, GenericTypeParameterBuilder[] parameters, MethodBuilder methodToInvoke)
{
var method = builder.DefineMethod("InvokeOnTarget",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot |
MethodAttributes.Virtual | MethodAttributes.Final, CallingConventions.HasThis);
method.SetReturnType(typeof(void));
var generator = method.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, target);
generator.Emit(OpCodes.Callvirt, methodToInvoke.MakeGenericMethod(parameters));
generator.Emit(OpCodes.Ret);
return method;
}
private static ConstructorBuilder GenerateCtor(TypeBuilder type, TypeBuilder builder, FieldBuilder target)
{
var constructor =
builder.DefineConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
CallingConventions.HasThis, new Type[] {type});
var generator = constructor.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Call, typeof (object).GetConstructors().Single());
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Stfld, target);
generator.Emit(OpCodes.Ret);
return constructor;
}
private static void GenerateSomeMethod(MethodBuilder method, TypeBuilder invocation, GenericTypeParameterBuilder[] parameters, ConstructorBuilder nestedCtor, MethodBuilder nestedMethod)
{
method.SetReturnType(typeof(void));
var genericType = invocation.MakeGenericType(parameters);
var constructor = TypeBuilder.GetConstructor(genericType, nestedCtor);
var methodInfo = TypeBuilder.GetMethod(genericType,nestedMethod);
var generator = method.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Newobj, constructor);
generator.Emit(OpCodes.Callvirt, methodInfo);
generator.Emit(OpCodes.Ret);
}
}
public interface IFoo
{
void SomeMethod<TBase, TInherited>() where TInherited : TBase;
}
public interface IInvocation
{
void InvokeOnTarget();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment