Created
March 1, 2019 03:55
-
-
Save TheBuzzSaw/cdfe8012b50114500853240a940ab2a3 to your computer and use it in GitHub Desktop.
EmitTest
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; | |
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