VivekR said:
* In your example, does the runtime IL code call an instance method of
class App ?
The IL I generated calls a passed-in delegate. Delegates are objects which
have a method called "Invoke". When you call a delegate in C#, the
compiler compiles it as a call to the instance method "Invoke" on the
delegate instance.
So, in order for the IL to call this Invoke method in my example, it needs
to do three things:
* Load the object reference (i.e. the delegate) onto the stack. This will
be the 'this' reference for the method call later on.
* Load the arguments to the method call. In the case of my example, the
Invoke method's arguments are the same as the delegate's method arguments,
that is to say a single argument of type string.
* Actually invoke the (non-virtual) instance method "Invoke".
So, my code calls an instance method called "Invoke" on the object
reference "SomeMethod reference" passed as a parameter to the
CompileMethod method.
* And I do not exactly understand why you are using List<object>, which
will contain multiple objects in it.
The reason I used List<object> is because it grows automatically, and it
can be converted easily to an object[] with the method ToArray(). The
reason I use object[] as the 'this' pointer associated with the created
delegate (passed to DynamicMethod.CreateDelegate) is because it is a
general solution (i.e. it will work in all cases) to the problem: "How to
load an object reference onto the stack?", for any number of object
references of any type.
* Why are you comparing
?
* In the statements
cg.Emit(OpCodes.Ldarg_0);
cg.Emit(OpCodes.Ldc_I4, index);
cg.Emit(OpCodes.Ldelem_Ref);
When you Ldelem_Ref, do you mean to say that the value loaded is the
'this' [ie the App's object reference].
With 'ldarg 0' I'm loading the first argument to the function onto the
stack. This will be the object reference associated with the delegate
which was invoked. When I created the delegate with
DynamicMethod.CreateDelegate, I passed in an 'object[]' as the object
reference associated with the delegate. That means that an 'object[]'
reference is the first parameter passed to the function. (Make sure you're
fully aware of how .NET delegates work - they are a pair of (object
reference, method reference).)
With ldc.i4 <index> I'm loading the index to grab out of the array onto
the stack. And with ldelem.ref I'm copying the object reference at the
given index out of the object array and onto the stack.
* Summarizing my required in your example's terms
- App must create a dynamic method [it does using Dynamic
Method].
- The IL code in the dynamic method must call a instance
method, say CallBackMethod, of App. [I am not clear if it does].
And for calling the CallBackMethod, i need to load the
object reference of App, and call the method.
Bear with me for my ignorance, cuz i feel this one is complex and
pretty hard to debug where it fails.
OK. Here's a simpler example:
---8<---
using System;
using System.Reflection;
using System.Reflection.Emit;
class App
{
delegate void SomeMethod(string arg);
static void Main()
{
SomeMethod compiled = CreateCall(new App(), "TargetMethod");
compiled("Hello World!");
}
public void TargetMethod(string arg)
{
Console.WriteLine("Target Method got called with '{0}'.", arg);
}
static SomeMethod CreateCall(object reference, string methodName)
{
if (reference == null)
throw new NullReferenceException(
"'reference' can't be null.");
DynamicMethod result = new DynamicMethod("f", typeof(void),
new Type[] { reference.GetType(), typeof(string) },
typeof(App));
ILGenerator cg = result.GetILGenerator();
// load 'this', the reference instance
cg.Emit(OpCodes.Ldarg_0);
// load 'arg', the argument for the target method.
cg.Emit(OpCodes.Ldarg_1);
MethodInfo method = reference.GetType().GetMethod(methodName,
new Type[] { typeof(string) });
if (method == null)
throw new Exception(
string.Format("Method '{0}' not found.", methodName));
if (method.IsVirtual)
cg.Emit(OpCodes.Callvirt, method);
else
cg.Emit(OpCodes.Call, method);
cg.Emit(OpCodes.Ret);
return (SomeMethod) result.CreateDelegate(typeof(SomeMethod),
reference);
}
}
--->8---
-- Barry