Created
October 11, 2009 08:30
-
-
Save kkozmic/207542 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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