Skip to content

Instantly share code, notes, and snippets.

@TheOtherBlack
Created March 12, 2018 20:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TheOtherBlack/33cb7d57d94a5feeaa956e01c07dfbc3 to your computer and use it in GitHub Desktop.
Save TheOtherBlack/33cb7d57d94a5feeaa956e01c07dfbc3 to your computer and use it in GitHub Desktop.
Second Part for Lowlevel IL - Defining our type with properties and methods
using System;
using System.Reflection;
using System.Reflection.Emit;
public interface IMagicType
{
string MyAutoProperty { get; set; }
string DoStuffWithMyProperty();
}
public class MagicTypeA : IMagicType
{
public string MyAutoProperty { get; set; }
public string DoStuffWithMyProperty()
{
MyAutoProperty = string.Format("Hello world! 123");
return MyAutoProperty;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("We have MagicTypeA with MyAutoProperty, it's a compiled version from C#:");
var typeA = new MagicTypeA();
Console.WriteLine("Called DoStuffWithMyProperty(): {0}", typeA.DoStuffWithMyProperty());
Console.WriteLine("Now attempting to implement the same as above in Runtime IL!");
// Define a new Dynamic Assembly to store our emitted types and code in
var dynaAssemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("MyDynamicAssembly"), AssemblyBuilderAccess.Run);
// Every assembly need a module!
var moduleBuilder = dynaAssemblyBuilder.DefineDynamicModule("MyDynamicModule");
// And let's define our new type that implements the interface matching that of IMagicType
var magicTypeBuilder = moduleBuilder.DefineType("MagicTypeB", TypeAttributes.Public, null, new[] { typeof(IMagicType) });
// Let's define private field so it could be used by our property!
var fieldForPropertyBuilder = magicTypeBuilder.DefineField("magicField", typeof(string), FieldAttributes.Private);
// Let's define our Property!
var propertyBuilder = magicTypeBuilder.DefineProperty("MyAutoProperty", PropertyAttributes.HasDefault, typeof(string), null);
// Let's define the Getter Method
var getterMethodBuilder = magicTypeBuilder.DefineMethod(
"GetProperty",
// This is publicly accessible method through Property
// This is set to virtual to allow this function to override Interface method
MethodAttributes.Public | MethodAttributes.Virtual,
typeof(string),
Type.EmptyTypes
);
var il = getterMethodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // Load 'This' onto stack
il.Emit(OpCodes.Ldfld, fieldForPropertyBuilder); // Load 'magicField' value onto stack
il.Emit(OpCodes.Ret); // Return 'magicField' value
propertyBuilder.SetGetMethod(getterMethodBuilder); // Make that our getter method!
// Let's define the Setter Method
var setterMethodBuilder = magicTypeBuilder.DefineMethod(
"SetProperty",
// This is publicly accessible method through Property
// This is set to virtual to allow this function to override Interface method
MethodAttributes.Public | MethodAttributes.Virtual,
typeof(void),
new[] { typeof(string) }
);
il = setterMethodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // Load 'This' onto stack
il.Emit(OpCodes.Ldarg_1); // Load new value paramter onto stack
il.Emit(OpCodes.Stfld, fieldForPropertyBuilder); // Store new value parameter in 'magicField'
il.Emit(OpCodes.Ret); // Return nothing
propertyBuilder.SetSetMethod(setterMethodBuilder); // Make that our setter method!
// Override Interface Methods for Property Getter and Setter
var interfaceProperty = typeof(IMagicType).GetProperty("MyAutoProperty");
magicTypeBuilder.DefineMethodOverride(getterMethodBuilder, interfaceProperty.GetMethod);
magicTypeBuilder.DefineMethodOverride(setterMethodBuilder, interfaceProperty.SetMethod);
// Let's define our DoStuffWithMyProperty!
var doMagicMethod= magicTypeBuilder.DefineMethod("DoStuffWithMyProperty", MethodAttributes.Public | MethodAttributes.Virtual, typeof(string), null);
il = doMagicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // Load This onto stack
il.Emit(OpCodes.Dup); // Duplicate the last added item in stack
il.Emit(OpCodes.Ldstr, "Hello world! 123"); // Load a constant string reference to "Hello world! 123" onto stack
il.Emit(OpCodes.Stfld, fieldForPropertyBuilder); // Pop both This and String Reference above Store string reference into field
il.Emit(OpCodes.Ldfld, fieldForPropertyBuilder); // Pop the very first This item and add value of field onto stack
il.Emit(OpCodes.Ret); // Pop field value off from stack and return it!
// Finally override Interface method for DoStuffWithMyProperty
magicTypeBuilder.DefineMethodOverride(doMagicMethod, typeof(IMagicType).GetMethod("DoStuffWithMyProperty"));
// Create our type by constructing all of the pieces above
var ourNewType = magicTypeBuilder.CreateType();
// Create a new instance and you can access it through the use of Interface with ease.
var MagicTypeB = (IMagicType)Activator.CreateInstance(ourNewType);
Console.WriteLine("We have MagicTypeB with MyAutoProperty, it's emitted during runtime:");
Console.WriteLine("Called DoStuffWithMyProperty(): {0}", MagicTypeB.DoStuffWithMyProperty());
Console.ReadLine();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment