Created
November 30, 2016 20:18
-
-
Save kosmakoff/d5a2d006624919b0487b63610b2193fd to your computer and use it in GitHub Desktop.
Simple class that builds the type implementing arbitrary interface in-memory, and then constructs it and returns
This file contains 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; | |
using System.Reflection; | |
using System.Reflection.Emit; | |
namespace CodeGenDemo | |
{ | |
static class CodeGenerator | |
{ | |
public static T GenerateStub<T>() | |
{ | |
var interfaceType = typeof(T); | |
var typeName = "StubFor" + interfaceType.Name.TrimStart('I'); | |
var assemblyName = new AssemblyName("DynamicAssembly"); | |
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); | |
var module = assemblyBuilder.DefineDynamicModule("DynamicModule"); | |
var typeBuilder = module.DefineType(typeName, TypeAttributes.Public); | |
typeBuilder.AddInterfaceImplementation(interfaceType); | |
var methods = interfaceType.GetMethods(); | |
var objType = typeof(object); | |
var objCtor = objType.GetConstructor(Type.EmptyTypes); | |
// add constructor | |
var constructorMethodInfo = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); | |
var ilGenerator = constructorMethodInfo.GetILGenerator(); | |
ilGenerator.Emit(OpCodes.Ldarg_0); | |
ilGenerator.Emit(OpCodes.Call, objCtor); | |
ilGenerator.Emit(OpCodes.Ret); | |
foreach (var methodInfo in methods) | |
{ | |
var returnType = methodInfo.ReturnType; | |
if (returnType == typeof(int)) | |
{ | |
var intMethodBuilder = typeBuilder.DefineMethod(methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, typeof(int), Type.EmptyTypes); | |
ilGenerator = intMethodBuilder.GetILGenerator(); | |
ilGenerator.Emit(OpCodes.Ldc_I4, 42); | |
ilGenerator.Emit(OpCodes.Ret); | |
typeBuilder.DefineMethodOverride(intMethodBuilder, methodInfo); | |
} | |
if (returnType == typeof(string)) | |
{ | |
var stringMethodBuilder = typeBuilder.DefineMethod(methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, typeof(string), Type.EmptyTypes); | |
ilGenerator = stringMethodBuilder.GetILGenerator(); | |
var lb1 = ilGenerator.DefineLabel(); | |
ilGenerator.Emit(OpCodes.Ldstr, "Hello, World!"); | |
ilGenerator.Emit(OpCodes.Ret); | |
typeBuilder.DefineMethodOverride(stringMethodBuilder, methodInfo); | |
} | |
} | |
var type = typeBuilder.CreateType(); | |
var constructor = type.GetConstructor(Type.EmptyTypes); | |
var instance = (T)constructor.Invoke(new object[0]); | |
return instance; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage note
Only interfaces with methods with no params and returning
int
andstring
are supported.