ILGenerator call instance method with parameter - c#

I am trying to construct an instance of a generic type and call a method on that instance. Then return the result of the method.
MethodInfo methodInfo = ...;
...
var genericType = typeof(GenericType<>).MakeGenericType(typeof(TOutput));
il.Emit(OpCodes.Newobj, genericType.GetConstructor(Type.EmptyTypes));
il.Emit(OpCodes.Ldobj, methodInfo);
il.Emit(OpCodes.Callvirt, genericeClientHelper.GetMethod("MethodName", new Type[] { typeof(MethodInfo) }));
il.Emit(OpCodes.Ret);
I keep getting a 'System.BadImageFormatException: 'Bad class token.'' exception.
GenericType class looks like this
public class GenericType<T>
{
public T MethodName(MethodInfo methodInfo)
{
...
}
}

You're confusing the boundary between the generated program, and the generating program.
Specifically, your generating program, when run, constructs an instance of an object (a MethodInfo instance) and then attempts to generate a program that uses that instance - which it can't because that instance doesn't exist in the generated program, it exists in the memory of the generating program.
You have to construct the instance of MethodInfo inside your generated program - you have to write the Emit code to generate the IL that constructs the MethodInfo instance.
What you're trying to do makes about as much sense as doing the following:
Person person = new Person( "Antiduh", "United States" );
var genericType = typeof(GenericType<>).MakeGenericType(typeof(TOutput));
il.Emit(OpCodes.Newobj, genericType.GetConstructor(Type.EmptyTypes));
// This doesn't make sense. The object referred to by
// my `person` variable doesn't exist in the generated program.
il.Emit(OpCodes.Ldobj, person);
il.Emit(OpCodes.Callvirt, genericeClientHelper.GetMethod("MethodName", new Type[] { typeof(MethodInfo) }));
il.Emit(OpCodes.Ret);
Thats problem number 1.
Problem number 2 is that you're using the wrong opcode when trying to provide an argument to a method - Ldobj doesn't do what you think it does.
Instead of using Ldobj, you'll have to load the reference by whatever means you fix your generation code to create the internal methodInfo. It'll probably be local, so you'll probably end up using Ldloc or some form thereof.
To come full circle, the reason why you're getting the error "Bad class token" is that the value that is supposed to follow Ldobj in the compiled IL is supposed to be a class metadata token. What you provided was not a class token, hence the error.
As a demonstration, below is a complete program that emulates what you're attempting to do.
private static void BuildAssembly()
{
AssemblyName assemblyName;
AssemblyBuilder assmBuilder;
ModuleBuilder modBuilder;
assemblyName = new AssemblyName( "Generated" );
// Note the save directory is the directory containing this project's solution file.
assmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
assemblyName,
AssemblyBuilderAccess.RunAndSave,
Assembly.GetExecutingAssembly().Location + #"\..\..\..\.."
);
modBuilder = assmBuilder.DefineDynamicModule(
assemblyName.Name,
assemblyName.Name + ".dll",
true
);
/*
* public class GenericsDemo {
* }
*/
TypeBuilder typeBuilder = modBuilder.DefineType(
"Generated.GenericsDemo",
TypeAttributes.Public
);
BuildCallListMethod( typeBuilder );
typeBuilder.CreateType();
assmBuilder.Save( assemblyName.Name + ".dll" );
}
private static void BuildCallListMethod( TypeBuilder typeBuilder )
{
// public void CallList() {
// List<object> list = new List<object>();
// object thing = new object();
// list.Add(thing);
// }
var listOfObject = typeof( List<object> );
var objType = typeof( object );
// public void CallList() {
var method = typeBuilder.DefineMethod(
"CallList",
MethodAttributes.Public | MethodAttributes.HideBySig,
CallingConventions.HasThis
);
var gen = method.GetILGenerator();
// List<int> list;
var listLocal = gen.DeclareLocal( listOfObject );
listLocal.SetLocalSymInfo( "list" );
// object thing;
var thingLocal = gen.DeclareLocal( objType );
thingLocal.SetLocalSymInfo( "thing" );
// list = new List<object>();
gen.Emit( OpCodes.Newobj, listOfObject.GetConstructor( Type.EmptyTypes ) );
gen.Emit( OpCodes.Stloc_0 );
// thing = new object();
gen.Emit( OpCodes.Newobj, objType.GetConstructor( Type.EmptyTypes ) );
gen.Emit( OpCodes.Stloc_1 );
// list.Add( thing );
gen.Emit( OpCodes.Ldloc_0 ); // loads `list`.
gen.Emit( OpCodes.Ldloc_1 ); // loads `thing`.
gen.EmitCall( OpCodes.Callvirt, listOfObject.GetMethod( "Add" ), null );
gen.Emit( OpCodes.Ret );
}

Related

How do I create mutually callable MethodInfos from MethodBuilders created from LambdaExpressions?

I'm currently working on an compiler in C#, where the behaviour is defined by LambdaExpressions, and then using CompileToMethod, transformed into MethodBuilders and saved to DLL. All functions are public and static.
However, I could not find a way to extract usable MethodInfo (or another method of reference) from the MethodBuilder until the behaviour is defined and declaring type is created/sealed. That means that at that until that point, it is impossible to use Expression.Call to call these functions. That makes self-recursion or mutual referencing between two functions impossible.
I ended up using Reflection to invoke the functions at runtime, but it's very suboptimal, and I'm still curious if there's a better way.
How do i ensure functions created with LambdaExpression.CompileToMethod(MethodBuilder) can self-call?
Alternatively, is there any other way to use LambdaExpressions which would allow this and support saving as a static method to a dll?
I hope this helps.
This is complete code example which produces runtime defined type with single static recursive method.
For the simplicity of the example the recursive method is infinite - at the end of the Main method the recursive method is called
static void Main(string[] args)
{
var moduleBuilder = CreateDynamicModuleBuilder();
var typeBuilder = moduleBuilder.DefineType("Person", TypeAttributes.Public | TypeAttributes.Class);
var methodBuilder = typeBuilder.DefineMethod("SayHello", MethodAttributes.Static | MethodAttributes.Public);
var methodExpression = CreateRecursiveExpression();
var lambda = Expression.Lambda(methodExpression);
lambda.CompileToMethod(methodBuilder);
var typeInfo = typeBuilder.CreateType();
var methodInfo = typeInfo.GetMethod("SayHello", BindingFlags.Public | BindingFlags.Static);
methodInfo.Invoke(null, null);
}
private static Expression CreateRecursiveExpression()
{
var methodInfo = typeof(Console).GetMethod("WriteLine", new[] { typeof(String) });
var arg = Expression.Constant("Hello");
var consoleCall = Expression.Call(methodInfo, arg);
var sayHelloActionVariable = Expression.Variable(typeof(Action), "sayHelloAction");
var block = Expression.Block(
new[] { sayHelloActionVariable },
Expression.Assign(
sayHelloActionVariable,
Expression.Lambda(
Expression.Block(
consoleCall,
Expression.Invoke(sayHelloActionVariable)
)
)
),
Expression.Invoke(sayHelloActionVariable)
);
return block;
}
private static ModuleBuilder CreateDynamicModuleBuilder()
{
var name = new AssemblyName("Example.DynamicRecursion");
var am = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
var mb = am.DefineDynamicModule(name.Name, $"{name.Name}.dll");
return mb;
}
This code will create type with the following signature
public class Person
{
public static void SayHello()
{
Action sayHelloAction;
sayHelloAction = () =>
{
Console.WriteLine("Hello");
sayHelloAction();
}
sayHelloAction();
}
}

How do I work around the error "ByRef return value not supported in reflection invocation" in C#?

I have a .Net library supplied by a third party. I did reflection on one of their classes and found a member method. The signature was...
Byte& FooBar()
So, I wanted to call this method through reflection and got the exception "ByRef return value not supported in reflection invocation."
Here is what I've tried...
var strm = new TheirClass();
var t = strm.GetType();
var ms = t.GetMembers(
BindingFlags.Static|BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (var m in ms)
{
Debug.WriteLine(String.Format("Name: {0}: {1}", m.Name, m.ToString()));
// ...
// Name: FooBar: Byte& FooBar()
// ...
}
var meth = t.GetMethod("FooBar");
object returnValue = meth.Invoke(strm, new object[] { }); //throw exception
I have tried supplying parameters as in calling functions with ref parameters, but that made no difference.
I would like to work around this exception in C#.
Per the comments: here is how it can be done from CIL, which can be generated from C#.
I was hoping to use a DynamicMethod, but I cannot manage to get this working without creating a custom delegate type at runtime, so I needed to use AssemblyBuilder instead.
using System;
using System.Reflection;
using System.Reflection.Emit;
public delegate void CallBadFunction(Delegate d, Callback c);
public delegate void Callback(ref int i);
static class Program
{
static int i;
static object BadMethod()
{
return i;
}
static MethodInfo GetBadMethod()
{
return typeof(Program).GetMethod("BadMethod", BindingFlags.Static | BindingFlags.NonPublic);
}
static void Main()
{
var badMethod = GetBadMethod();
var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("-"), AssemblyBuilderAccess.Run);
var module = assembly.DefineDynamicModule("-");
var badDelegate = module.DefineType("BadDelegateType", TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed, typeof(MulticastDelegate));
var badDelegateCtor = badDelegate.DefineConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[] { typeof(object), typeof(IntPtr) });
badDelegateCtor.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
var badDelegateInvoke = badDelegate.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.HideBySig, typeof(int).MakeByRefType(), Type.EmptyTypes);
badDelegateInvoke.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
var badDelegateType = badDelegate.CreateType();
var method = module.DefineGlobalMethod("-", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new[] { typeof(Delegate), typeof(Callback) });
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, badDelegate);
il.Emit(OpCodes.Callvirt, badDelegateInvoke);
il.Emit(OpCodes.Callvirt, typeof(Callback).GetMethod("Invoke"));
il.Emit(OpCodes.Ret);
module.CreateGlobalFunctions();
var callBadFunction = (CallBadFunction)Delegate.CreateDelegate(typeof(CallBadFunction), module.GetMethod("-"));
callBadFunction(badMethod.CreateDelegate(badDelegateType), (ref int i) =>
{
i++;
});
}
}
After compiling this program, use ILDASM to disassemble it, and replace BadMethod's definition by
.method private hidebysig static int32&
BadMethod() cil managed
{
ldsflda int32 Program::i
ret
}
This turns it into a function returning int32&, which the following code will then manage to call. The only location C# allows int32& types is in function parameters (ref int), so to make the result usable, I used a callback function, which gets passed the return value of BadMethod.
Thank you "hvd" for pointing me in the right direction. After some thought, here is what I came up with. It's simpler, but please tell me if you see a flaw.
var theirObj = new TheirClass();
var t = theirObj.GetType();
var fooBar = t.GetMethod("FooBar"); // Byte& FooBar()
DynamicMethod dm = new DynamicMethod(
"MyFooBar",
MethodAttributes.Public | MethodAttributes.Static,
CallingConventions.Standard,
typeof(IntPtr),
new Type[] { typeof(TheirClass) },
typeof(TheirClass),
true);
var ilg = dm.GetILGenerator();
ilg.Emit(OpCodes.Ldarg_0);
ilg.Emit(OpCodes.Call, foobar);
ilg.Emit(OpCodes.Ret);
var del = dm.CreateDelegate(typeof(Func<TheirClass,IntPtr>));
var ret = (IntPtr)del.DynamicInvoke(theirObject);
byte[] buf = new byte[theirObj.FooBarSize()]; //no need for reflection/IL here
// not sure about the following, it works, but should it be inside an "unsafe" section?
Marshal.Copy(ret, buf, 0, buf.Length);
I put a simple wrapper around the offending method and IL doesn't care that I treat the Byte& as an IntPtr. I'm still not sure about doing a Copy without an unsafe wrapper. But this is good for now.

How to translate new object creation?

Not so long ago I started to learn to use System.Reflection.Emit namespace. I'm now trying to translate this code to use of ILGenerator:
MyClass c = new MyClass("MyClass");
c.Do(":D");
For this piece of code I have three questions: how to create object? how to call contructor and how to call method of class? Please help.
Here's a complete example that shows the necessary IL code.
You can test this in LINQPad:
void Main()
{
// Manual test first
MyClass c = new MyClass("MyClass");
c.Do(":D");
var method = new DynamicMethod("dummy", null, Type.EmptyTypes);
var il = method.GetILGenerator();
// <stack> = new MyClass("MyClass");
il.Emit(OpCodes.Ldstr, "MyClass");
il.Emit(OpCodes.Newobj, typeof(MyClass).GetConstructor(new[] { typeof(string) }));
// <stack>.Do(":D");
il.Emit(OpCodes.Ldstr, ":D");
il.Emit(OpCodes.Call, typeof(MyClass).GetMethod("Do", new[] { typeof(string) }));
// return;
il.Emit(OpCodes.Ret);
var action = (Action)method.CreateDelegate(typeof(Action));
action();
}
public class MyClass
{
public MyClass(string text)
{
Console.WriteLine("MyClass(" + text + ")");
}
public void Do(string text)
{
Console.WriteLine("Do(" + text + ")");
}
}
Output:
MyClass(MyClass)
Do(:D)
MyClass(MyClass)
Do(:D)
Incidentally, you can use LINQPad to get hold of the IL code for a particular example. Let me cut out the IL-part of the above example, like this (I removed the class as well, it's the same class):
void Main()
{
MyClass c = new MyClass("MyClass");
c.Do(":D");
}
By executing this code, and then using the IL tab of the output, you can see the generated code:
The two instructions stloc.0 and ldloc.0 is the variable in the code.
The IL I emitted first is akin to this piece of code:
new MyClass("MyClass").Do(":D");
ie. no variable, just temporary storage on the stack, and indeed:

Dynamic Property setter c#

Hi guys I am trying to generate a delegate at runtime using Dynamic Methods and the ILGenerator to invoke the Setter of a property on an object.....
private static GenericIntSetter CreateIntSetMethod(PropertyInfo propertyInfo)
{
MethodInfo setMethod = propertyInfo.GetSetMethod();
if (setMethod == null)
return null;
Type[] arguments = new Type[2];
arguments[0] = typeof(Person);
arguments[1] = typeof(int);
DynamicMethod setter = new DynamicMethod(
String.Concat("_Set", propertyInfo.Name, "_"),
typeof(void), arguments, propertyInfo.DeclaringType);
ILGenerator generator = setter.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
generator.Emit(OpCodes.Ldarg_1);
if (propertyInfo.PropertyType.IsClass)
{
generator.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
}
else
{
generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
}
generator.EmitCall(OpCodes.Callvirt, setMethod, null);
generator.Emit(OpCodes.Ret);
return (GenericIntSetter)setter.CreateDelegate(typeof(GenericIntSetter));
}
When I call this method and I invoke the delete I get a corrupt memory error, any ideas?
Yep. It's really complicated to do that, but not impossible.
I have a open source project just for that http://mirrormirror.codeplex.com
In http://mirrormirror.codeplex.com/SourceControl/changeset/view/66562#869731 you will find the code for all the emit I need to do. It should be easy to find the setter implementation.
Hope it helps

Generating IL for Recursive Methods

I tried to generate IL for recursive method using following strategy,
Firstly I defined type using following code snippet
private void InitializeAssembly(string outputFileName)
{
AppDomain appDomain = AppDomain.CurrentDomain;
AssemblyName assemblyName = new AssemblyName(outputFileName);
assemblyBuilder = appDomain.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.Save);
moduleBuilder = assemblyBuilder.DefineDynamicModule(outputFileName, outputFileName + ".exe");
typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);
methodBuilder = typeBuilder.DefineMethod("Main",
MethodAttributes.Static | MethodAttributes.Public,
typeof(void),
System.Type.EmptyTypes);
ilGen = methodBuilder.GetILGenerator();
}
Next I started to generate IL for recursive method as given below.
MethodBuilder method = typeBuilder.DefineMethod(
“MethodName”,
MethodAttributes.Static | MethodAttributes.Public,
NodeTypeToDotNetType(func.RetType),
parameters);
ILGenerator ilOfMethod = method.GetILGenerator();
method.DefineParameter();
For calling method itself inside the method body I used following construct,
ilOfMethod.Emit(OpCodes.Call, typeBuilder.GetMethod("MethodName", new System.Type[] {typeof(arg1),typeof(arg2),etc}));
Finally save generated assembly using following method.
private void SaveAssembly(string outputFileName)
{
ilGen.Emit(OpCodes.Ret);
typeBuilder.CreateType();
moduleBuilder.CreateGlobalFunctions();
assemblyBuilder.SetEntryPoint(methodBuilder);
assemblyBuilder.Save(outputFileName + ".exe");
}
Unfortunately this is not working since recursive method calling construct, inside the method returns null. Issue here is that recursive call inside the method ( i.e. ilOfMethod.Emit(OpCodes.Call, typeBuilder.GetMethod("MethodName", new System.Type[] {typeof(arg1),typeof(arg2),etc}));
) returns null. Since we actually create the type inside the SaveAssembly() method, this is acceptable. So my question is that: is it possible to generate IL for recursive methods using above construct? If it is not possible, Please let me know that alternative constructs for generating IL for recursive methods.
I haven't tested it, but if I remember correctly you should be able to simply use the result of DefineMethod to emit the Call instruction:
MethodBuilder method = typeBuilder.DefineMethod("MethodName", ...);
...
ILGenerator ilOfMethod = method.GetILGenerator();
...
ilOfMethod.Emit(OpCodes.Call, method);

Categories