Library for runtime MSIL functions compilation
-
Create ILGen object
ILGen<[Method delegate type]> gen = new ILGen<[Method delegate type]>([Mathod name], [enable private fields and classes access]);
-
Write code with statements
gen.Line
for statements- Use class Expr to use operators (Example:
Expr.Mul(gen.args[0], gen.Const(3.5f))
,Expr.Greater(gen.args[0], 0)
) - To set value use Set method (Example:
gen.Line(i.Set(0));
) !Set is the statement and must be in gen.Line
- Use class Expr to use operators (Example:
gen.Return
to return valuegen.If
/gen.ElseIf
/gen.Else
/gen.EndIf
for if constructiongen.While
/gen.EndWhile
for while cycles
-
Call
gen.compile([enable debug info]);
to compile your function
Maybe you need only to compile function-caller / constructor / setter / getter for unknown type? You can use ILTemplate for these tasks:
ILTemplate.CommonMemberGetter
- for static and instance class members get. Returns Func<object, object>, where the first argument - object instance (if instance member) and the return value - field valueILTemplate.StaticMemberGetter
- for stastic class members get. As CommonMember getter, but the return function doesn't receive the object instance argumentILTemplate.InstanceMemberGetter
- for instance class members get. The first argument of the return function - object instance, return value - field value
CommonMemberSetter
- for static and instance class members set. Returns Action<object, object> where first argument - object instance (for instance fields) and the second - set valueStaticMemberSetter
- for static members set. Result Action< object > is without object instance argInstanceMemberSetter
for instance members set. Returns Action<object, object> where first argument - object instance and second - set value
- Use
CommonObjectCreator
to compile function Func<object[], object>, that calls constructor with args in array of object and returns a new object instance
CommonCallShell
- call shell for static and instance class methods, with and without return type. Returns Func<object, object[], object> , where the first argument - class instance (if calls instance function), the second - call function args array. Returns null, if call method has no return typeCommonStaticCallShell
- call shell for static class methods with and without return type. Returns Func<object[], object>, where the first argument - call function args array.StaticActionCallShell
- call shell for static class methods without return type. Returns Action<object[]>, where the first argument - call function args array.StaticFunctionCallShell
- call shell for static class methods without return type. Returns Func<object[], object>, where the first argument - call function args array.CommonInstanceCallShell
- call shell for instance class methods with and without return type. Returns Func<object, object[], object> where the first arg - object instance, the second - function call args array. Returns null, if the call method has no return typeInstanceActionCallShell
- call shell for instance class methods without return type. Returns Action<object, object[]> where the first arg - object instance, the second - function call args array.InstanceFunctionCallShell
- call shell for instance class methods with return type. Returns Func<object, object[], object> where the first arg - object instance, the second - function call args array.
Function returns (first arg) * 3.5
ILGen<Func<int, float>> gen = new ILGen<Func<int, float>>("Example1_func", true);
//Function
gen.Return( Expr.Mul(gen.args[0], gen.Const(3.5f)) ) ;
var func = gen.compile(true); //Our function
Console.WriteLine("Result: {0}", func(15));
If/elseif/else constructions
var gen = new ILGen<Action<int>>("TestFunc5_1", true);
//Function
gen.If(Expr.Greater(gen.args[0], 0));
//If arg0 > 0
gen.Line(Expr.CallStatic(typeof(Console), "WriteLine", "{0} is positive", Expr.CreateArray(typeof(object), gen.args[0])));
gen.ElseIf(Expr.Less(gen.args[0], 0));
//Else if arg0 < 0
gen.Line(Expr.CallStatic(typeof(Console), "WriteLine", "{0} is negative", Expr.CreateArray(typeof(object), gen.args[0])));
gen.Else();
//else (arg0 == 0)
gen.Line(Expr.CallStatic(typeof(Console), "WriteLine", "Zero"));
gen.EndIf();
var func = gen.compile(true);
Fibonacci numbers array gen
var gen = new ILGen<Func<int, long[]>>("TestFunc6", true);
//Function
ILVar resultArray = gen.DeclareVar(typeof(long[]));
ILVar arrayIndex = gen.DeclareVar(typeof(int));
gen.Line(resultArray.Set(Expr.InitArray(typeof(long), gen.args[0])));
gen.Line(resultArray.Index(0).Set(0));
gen.Line(resultArray.Index(1).Set(1));
gen.Line(arrayIndex.Set(2));
gen.While(Expr.NotEquals(arrayIndex, resultArray.ArrayLength));
gen.Line(resultArray.Index(arrayIndex).Set(resultArray.Index(arrayIndex - 1) + resultArray.Index(arrayIndex - 2)));
gen.Line(arrayIndex.Set(arrayIndex + 1));
gen.EndWhile();
gen.Return(resultArray);
var func = gen.compile(true);
Double fields of unknown type sum function
var gen = new ILGen<Func<T, double>>(typeof(T).Name + "_fields_sum", true);
ILVar counter = gen.DeclareVar<double>();
gen.Line(counter.Set(0.0));
foreach(FieldInfo fieldInfo in typeof(T).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(info => info.FieldType == typeof(double)))
gen.Line(counter.Set(counter + gen.args[0].Field(fieldInfo)));
gen.Return(counter);
var func = gen.compile(true);
Create a matrix and output it to console
var gen = new ILGen<Action>("TestFunc14", true);
ILVar matrix = gen.DeclareVar(typeof(int[,]));
gen.Line(matrix.Set(Expr.CreateArray(typeof(int), new Expr[] {
1, 2, 3,
4, 5, 6,
7, 8, 9
}, new int[] { 3, 3})));
ILVar index1 = gen.DeclareVar(typeof(int));
gen.Line( index1.Set(0) );
ILVar index2 = gen.DeclareVar(typeof(int));
gen.Line( index2.Set(0) );
ILVar lineString = gen.DeclareVar(typeof(string));
gen.While( Expr.Less(index1, matrix.GetArrayDimensionLength(0)) );
gen.Line( lineString.Set("") );
gen.Line( index2.Set(0) );
gen.While( Expr.Less(index2, matrix.GetArrayDimensionLength(1)) );
gen.Line( lineString.Set(Expr.Add(Expr.Add(lineString, matrix.Index(index1, index2).CompatiblePass(typeof(string))), "; ")) );
gen.Line( index2.Set(Expr.Add(index2, 1)) );
gen.EndWhile();
gen.Line(Expr.CallStatic(typeof(Console), "WriteLine", lineString));
gen.Line( index1.Set(Expr.Add(index1, 1)) );
gen.EndWhile();
var func = gen.compile(true);
Create delegate instance and call it
delegate int TestDelegate(int a, int b);
public static int testAddition(int a, int b) {
Console.WriteLine($"Call testAddition with args a = {a}, b = {b}");
return a + b;
}
public static void testFunc17() {
var gen = new ILGen<Func<int, int, int>>("TestFunc17", true);
ILVar delegateVar = gen.DeclareVar(typeof(TestDelegate));
gen.Line(delegateVar.Set(Expr.CreateDelegate(typeof(TestDelegate), Expr.NULL, typeof(Program).GetMethod("testAddition", BindingFlags.Public | BindingFlags.Static))));
gen.Return(delegateVar.Invoke(gen.args[0], gen.args[1]));
var func = gen.compile(true);
int result = func(5, 6);
Console.WriteLine($"Result: {result}");
}
IL compile
IL create by templates
To see MSIL code, I used ILSpy. Codes to view MSIL are in ShowCode