Skip to content

Instantly share code, notes, and snippets.

@TheBuzzSaw
Created March 1, 2019 03:55
Show Gist options
  • Save TheBuzzSaw/cdfe8012b50114500853240a940ab2a3 to your computer and use it in GitHub Desktop.
Save TheBuzzSaw/cdfe8012b50114500853240a940ab2a3 to your computer and use it in GitHub Desktop.
EmitTest
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace EmitTest
{
public interface IWorker
{
void DoTheThing(int a, string b, Guid c);
void DoTheOtherThing(float a, DateTime b);
}
class Program
{
static T Map<T>() where T : class
{
T result = null;
var interfaceType = typeof(T);
if (!interfaceType.IsInterface)
throw new ArgumentException("Type T must be interface.");
var assemblyName = new AssemblyName("Kelly.Emit");
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
assemblyName,
AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
var typeBuilder = moduleBuilder.DefineType("DarkMap", TypeAttributes.Public);
typeBuilder.AddInterfaceImplementation(interfaceType);
var staticMethodBuilder = typeBuilder.DefineMethod(
"Blam",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.PinvokeImpl,
CallingConventions.Standard,
typeof(int),
null);
var flags = staticMethodBuilder.GetMethodImplementationFlags();
staticMethodBuilder.SetImplementationFlags(flags | MethodImplAttributes.PreserveSig | MethodImplAttributes.Managed);
var constructorBuilder = typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
// var generator = constructorBuilder.GetILGenerator();
// generator.Emit(OpCodes.Ret);
var writeLineMethod = typeof(Console)
.GetMethods()
.Single(m => m.Name == "WriteLine" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(string));
foreach (var interfaceMethod in interfaceType.GetMethods())
{
Console.WriteLine(interfaceMethod.Name);
var parameterTypes = interfaceMethod
.GetParameters()
.Select(p => p.ParameterType)
.ToArray();
var methodBuilder = typeBuilder.DefineMethod(
interfaceMethod.Name,
MethodAttributes.Public | MethodAttributes.Virtual,
CallingConventions.HasThis,
interfaceMethod.ReturnType,
parameterTypes);
var generator = methodBuilder.GetILGenerator();
// generator.Emit(OpCodes.Ldarg_0);
for (int i = 0; i < parameterTypes.Length; ++i)
{
var toStringMethod = parameterTypes[i]
.GetMethods()
.Single(m => m.Name == "ToString" && m.GetParameters().Length == 0);
if (parameterTypes[i].IsValueType)
generator.Emit(OpCodes.Ldarga_S, i + 1);
else
generator.Emit(OpCodes.Ldarg, i + 1);
generator.Emit(OpCodes.Call, toStringMethod);
generator.Emit(OpCodes.Call, writeLineMethod);
}
generator.Emit(OpCodes.Ret);
}
var type = typeBuilder.CreateType();
result = (T)Activator.CreateInstance(type);
return result;
}
static void HelpMe(int n)
{
Console.WriteLine(n.ToString());
}
static void Main(string[] args)
{
try
{
var worker = Map<IWorker>();
worker.DoTheThing(1, "yes", Guid.NewGuid());
worker.DoTheOtherThing(9.3f, DateTime.Now);
}
catch (Exception ex)
{
for (var e = ex; e != null; e = e.InnerException)
{
Console.WriteLine(e.GetType());
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment