public static Action<T> BuildFieldsPrinter<T>() where T : class { var type = typeof(T); var method = new DynamicMethod(Guid.NewGuid().ToString(), // typeof(void), // new[] {type}, // typeof(string), // , , , string true); // var il = method.GetILGenerator(); var fieldValue = il.DeclareLocal(typeof(object)); var toStringMethod = typeof(object).GetMethod("ToString"); var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach(var field in fields) { il.Emit(OpCodes.Ldstr, field.Name + ": {0}"); // stack: [format] il.Emit(OpCodes.Ldarg_0); // stack: [format, obj] il.Emit(OpCodes.Ldfld, field); // stack: [format, obj.field] if(field.FieldType.IsValueType) il.Emit(OpCodes.Box, field.FieldType); // stack: [format, (object)obj.field] il.Emit(OpCodes.Dup); // stack: [format, obj.field, obj.field] il.Emit(OpCodes.Stloc, fieldValue); // fieldValue = obj.field; stack: [format, obj.field] var notNullLabel = il.DefineLabel(); il.Emit(OpCodes.Brtrue, notNullLabel); // if(obj.field != null) goto notNull; stack: [format] il.Emit(OpCodes.Ldstr, "null"); // stack: [format, "null"] var printedLabel = il.DefineLabel(); il.Emit(OpCodes.Br, printedLabel); // goto printed il.MarkLabel(notNullLabel); il.Emit(OpCodes.Ldloc, fieldValue); // stack: [format, obj.field] il.EmitCall(OpCodes.Callvirt, toStringMethod, null); // stack: [format, obj.field.ToString()] il.MarkLabel(printedLabel); var writeLineMethod = typeof(Console).GetMethod("WriteLine", new[] { typeof(string), typeof(object) }); il.EmitCall(OpCodes.Call, writeLineMethod, null); // Console.WriteLine(format, obj.field.ToString()); stack: [] } il.Emit(OpCodes.Ret); return (Action<T>)method.CreateDelegate(typeof(Action<T>)); }
var il = dynamicMethod.GetILGenerator(); {..} // - il.Emit(OpCodes.Ldfld); // , FieldInfo {..} // - var compiledMethod = dynamicMethod.CreateDelegate(..); compiledMethod(..); // ←
var il = dynamicMethod.GetILGenerator(); {..} // - il.Emit(OpCodes.Box); // value type object, {..} // - var compiledMethod = dynamicMethod.CreateDelegate(..); compiledMethod(..); // ←
var il = dynamicMethod.GetILGenerator(); {..} // - var code = GetCode(..); // byte il.Emit(OpCodes.Ldc_I4, code); // int, byte {..} // - var compiledMethod = dynamicMethod.CreateDelegate(..); compiledMethod(..); // ←
var il = dynamicMethod.GetILGenerator(); {..} // - il.Emit(OpCodes.Call, abstractMethod); // , Callvirt Call {..} // - var compiledMethod = dynamicMethod.CreateDelegate(..); compiledMethod(..); // ←
var il = dynamicMethod.GetILGenerator(); {..} // - var keyGetter = typeof(KeyValuePair<int, int>).GetProperty("Key").GetGetMethod(); il.Emit(OpCodes.Ldarg_1); // 1 – KeyValuePair<int, int> il.Emit(OpCodes.Call, keyGetter); // Key KeyValuePair<int, int>, value type, // , {..} // - var compiledMethod = dynamicMethod.CreateDelegate(..); compiledMethod(..); // ←
var il = dynamicMethod.GetILGenerator(); {..} // - var toStringMethod = typeof(object).GetMethod("ToString"); il.Emit(OpCodes.Ldarga, 1); // 1 – int, il.Emit(OpCodes.Callvirt, toStringMethod); // int.ToString(), // value type constrained {..} // - var compiledMethod = dynamicMethod.CreateDelegate(..); compiledMethod(..); // ←
var il = dynamicMethod.GetILGenerator(); {..} // - var bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic; // value var valueField = typeof(KeyValuePair<int, string>).GetField("value", bindingFlags); il.Emit(OpCodes.Ldarga, 1); // 1 – KeyValuePair<string, int> il.Emit(OpCodes.Ldfld, valueField); // value KeyValuePair<string, int>, // KeyValuePair<string, int> KeyValuePair<int, string>, // key int string {..} // - var compiledMethod = dynamicMethod.CreateDelegate(..); var result = compiledMethod(..); // ← {..} // - result ←
static int Add(int x, double y) { return x + (int)y; }
var il = dynamicMethod.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); // 0 - int il.Emit(OpCodes.Ldarg_1); // 1 - double il.Emit(OpCodes.Add); // double int. il.Emit(OpCodes.Ret); var compiledMethod = dynamicMethod.CreateDelegate(..); var result = compiledMethod(..); // ←
static string Coalesce(string str) { return str ?? ""; }
var il = dynamicMethod.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); // stack: [str] il.Emit(OpCodes.Dup); // stack: [str, str] var notNullLabel = il.DefineLabel(); il.Emit(OpCodes.Brtrue, notNullLabel); // if(str != null) goto notNull; stack: [str] il.Emit(OpCodes.Ldstr, ""); // Oops, , str il.MarkLabel(notNullLabel); // : , il.Emit(OpCodes.Ret); var compiledMethod = dynamicMethod.CreateDelegate(..); compiledMethod(..); // ←
public static Action<T> BuildFieldsPrinter<T>() where T : class { var type = typeof(T); var method = new DynamicMethod(Guid.NewGuid().ToString(), // typeof(void), // new[] { type }, // typeof(string), // , , , string true); // using(var il = new GroboIL(method)) { var fieldValue = il.DeclareLocal(typeof(object), "fieldValue"); var toStringMethod = typeof(object).GetMethod("ToString"); var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach(var field in fields) { il.Ldstr(field.Name + ": {0}"); // stack: [format] il.Ldarg(0); // stack: [format, obj] il.Ldfld(field); // stack: [format, obj.field] if(field.FieldType.IsValueType) il.Box(field.FieldType); // stack: [format, (object)obj.field] il.Dup(); // stack: [format, obj.field, obj.field] il.Stloc(fieldValue); // fieldValue = obj.field; stack: [format, obj.field] var notNullLabel = il.DefineLabel("notNull"); il.Brtrue(notNullLabel); // if(obj.field != null) goto notNull; stack: [format] il.Ldstr("null"); // stack: [format, "null"] var printedLabel = il.DefineLabel("printed"); il.Br(printedLabel); // goto printed il.MarkLabel(notNullLabel); il.Ldloc(fieldValue); // stack: [format, obj.field] il.Call(toStringMethod); // stack: [format, obj.field.ToString()] il.MarkLabel(printedLabel); var writeLineMethod = typeof(Console).GetMethod("WriteLine", new[] { typeof(string), typeof(object) }); il.Call(writeLineMethod); // Console.WriteLine(format, obj.field.ToString()); stack: [] } il.Ret(); } return (Action<T>)method.CreateDelegate(typeof(Action<T>)); }
using(var il = new GroboIL(dynamicMethod)) { {..} // - il.Ldfld(); // ← {..} // - }
using(var il = new GroboIL(dynamicMethod)) { {..} // - il.Box(); // ← {..} // - }
using(var il = new GroboIL(dynamicMethod)) { {..} // - var code = GetCode(..); // byte il.Ldc_I4(code); // ← , int {..} // - }
using(var il = new GroboIL(dynamicMethod)) { {..} // - il.Call(abstractMethod); // ← , Callvirt {..} // - }
using(var il = new GroboIL(dynamicMethod)) { {..} // - var keyGetter = typeof(KeyValuePair<int, int>).GetProperty("Key").GetGetMethod(); il.Ldarg(1); // 1 – KeyValuePair<int, int> il.Call(keyGetter); // ← {..} // - }
using(var il = new GroboIL(dynamicMethod)) { {..} // - var toStringMethod = typeof(object).GetMethod("ToString"); il.Ldarga(1); // 1 – int, il.Call(toStringMethod); // ← {..} // - }
using(var il = new GroboIL(dynamicMethod)) { {..} // - var bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic; // value var valueField = typeof(KeyValuePair<int, string>).GetField("value", bindingFlags); il.Ldarga(1); // 1 – KeyValuePair<string, int> il.Ldfld(valueField); // ← {..} // - }
using(var il = new GroboIL(dynamicMethod)) { il.Ldarg(0); // 0 - int il.Ldarg(1); // 1 - double il.Add(); // ← il.Ret(); }
using(var il = new GroboIL(dynamicMethod)) { il.Ldarg(0); // stack: [str] il.Dup(); // stack: [str, str] var notNullLabel = il.DefineLabel("notNull"); il.Brtrue(notNullLabel); // if(str != null) goto notNull; stack: [str] il.Ldstr(""); // Oops, , str il.MarkLabel(notNullLabel); // ← il.Ret(); }
ldarg.0 // [List<T>] dup // [List<T>, List<T>] brtrue notNull_0 // [null] pop // [] ldc.i4.0 // [Int32] newarr T // [T[]] notNull_0: // [{Object: IList, IList<T>, IReadOnlyList<T>}] ldarg.1 // [{Object: IList, IList<T>, IReadOnlyList<T>}, Func<T, Int32>] call Int32 Enumerable.Sum<T>(IEnumerable<T>, Func<T, Int32>) // [Int32] ret // []
public abstract class Bazzze { public abstract int Sum(int x, double y); } public void Test() { var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly( new AssemblyName("DynAssembly"), AssemblyBuilderAccess.RunAndCollect); // , Assembly, var module = assembly.DefineDynamicModule("zzz", "zzz.dll", true); // true - var symWriter = module.GetSymWriter(); var typeBuilder = module.DefineType("Zzz", TypeAttributes.Public | TypeAttributes.Class, typeof(Bazzze)); var method = typeBuilder.DefineMethod( "Sum", MethodAttributes.Public | MethodAttributes.Virtual, // typeof(int), // new[] { typeof(int), typeof(double) }); // method.DefineParameter(1, ParameterAttributes.None, "x"); // method.DefineParameter(2, ParameterAttributes.None, "y"); // watch var documentName = typeBuilder.Name + "." + method.Name + ".cil"; var documentWriter = symWriter.DefineDocument(documentName, SymDocumentType.Text, SymLanguageType.ILAssembly, Guid.Empty); // using(var il = new GroboIL(method, documentWriter)) // documentWriter { il.Ldarg(1); // stack: [x] il.Ldarg(2); // stack: [x, y] il.Conv<int>(); // stack: [x, (int)y] il.Dup(); // stack: [x, (int)y, (int)y] var temp = il.DeclareLocal(typeof(int), "temp"); il.Stloc(temp); // temp = (int)y; stack: [x, (int)y] il.Add(); // stack: [x + (int)y] il.Ret(); File.WriteAllText(Path.Combine(DebugOutputDirectory, documentName), il.GetILCode()); } typeBuilder.DefineMethodOverride(method, typeof(Bazzze).GetMethod("Sum")); // var type = typeBuilder.CreateType(); var inst = (Bazzze)Activator.CreateInstance(type, new object[0]); inst.Sum(10, 3.14); }
Source: https://habr.com/ru/post/262711/
All Articles