How to call a MethodInfo? - c#

i have a MethodInfo object, that defines a method i want to call.
Except i need the object that MethodInfo came from.
pseudo-code:
void CallMethod(MethodInfo m)
{
Object o = Activator.CreateInstance(m.ClassType);
o.GetType().InvokeMember(m.Name, BindingFlags.InvokeMethod, null, o, null);
}
Except i don't know how to get the type of the class that MethodInfo belongs to.
How can i call a MethodInfo?

The MethodInfo doesn't know the target of the method call - the MethodInfo effectively belongs to the type, not one specific object.
You need to have an instance of the target type on which to call the method. You can find the type easily enough using MethodInfo.DeclaringType (inherited from MemberInfo.DeclaringType), but you may not have an instance at that point...
As noted by Reed, MemberInfo.ReflectedType may be more appropriate than DeclaringType, depending on how you were planning to use it.
You haven't explained anything about what you're doing, but it may be more appropriate to take an Action delegate instead of a MethodInfo, if the rest of your design could be changed appropriately.

This will create an object from the type that your MethodInfo is, and will invoke it for you on that new object.
void CallMethod(MethodInfo m)
{
Object o = Activator.CreateInstance(m.ReflectedType);
m.Invoke(o, null);
}

You can determine the type which defines the method by accessing the DeclaringType property of the MethodInfo object.

I may be misunderstanding the question, but it sounds like you're after a delegate rather than a MethodInfo.
void Main()
{
Object myObject = new ArrayList();
MethodInfo methodInfo = myObject.GetType().GetMethod("Clear");
Delegate method = Delegate.CreateDelegate(typeof(Action), myObject, methodInfo, true);
CallMethod(method);
}
void CallMethod(Delegate method)
{
method.DynamicInvoke();
}
There's clearly an easier way to acquire the delegate in this circumstance (method = new Action(myObject.Clear)), but I'm going on your question of needing to use a MethodInfo object.

Related

Why does `dynamicMethod.CreateDelegate(typeof(Action)).Method.Invoke(null,new object[0]);` throw an Exception?

This seems to work, providing a (weird) way to call an Action:
Action action = () => { };
action.Method.Invoke(action.Target, new object[0]);
This seems to work, providing a (helpful) way to create an Action:
var action = dynamicMethod.CreateDelegate(typeof(Action)) as Action;
action();
However, this throws an Exception:
var action = dynamicMethod.CreateDelegate(typeof(Action)) as Action;
action.Method.Invoke(action.Target, new object[0]); // Throws exception
MethodInfo must be a runtime MethodInfo object.
Question: Why is the above code snippet throwing an Exception?
Working code example
var dynamicMethod = new System.Reflection.Emit.DynamicMethod(
""
, typeof(void)
, new Type[0]
);
var ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ret);
var action = dynamicMethod.CreateDelegate(typeof(Action)) as Action;
try
{
action.Method.Invoke(action.Target, new object[0]);
}
catch (Exception exception)
{
System.Console.WriteLine(exception);
}
This causes the Console to write:
Exception thrown: 'System.ArgumentException' in mscorlib.dll
System.ArgumentException: MethodInfo must be a runtime MethodInfo object.
Parameter name: this
at System.Reflection.Emit.DynamicMethod.RTDynamicMethod.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
[...]
Thoughts
I've tried a bunch of variations on calling action.Method.Invoke(), but all sorts of variations on the call arguments don't seem to change the exception-message,
MethodInfo must be a runtime MethodInfo object.
My guess is that action.Method isn't a "runtime MethodInfo", despite being a "MethodInfo". I'm not really sure what the distinction between a runtime-MethodInfo and a non-runtime-MethodInfo might be, though.
MethodInfo is an abstract type, which has several implementations.
One of them is the internal type System.Reflection.RuntimeMethodInfo. This is what you get when you reflect the methods of existing runtime types:
Console.WriteLine(typeof(object).GetMethod("ToString").GetType().FullName); // System.Reflection.RuntimeMethodInfo
On the other hand, DynamicMethod.CreateDelegate uses another implementation of MethodInfo:
Console.WriteLine(action.Method.GetType().FullName); // System.Reflection.Emit.DynamicMethod+RTDynamicMethod
And it seems it does not support invocation by MethodInfo.Invoke.
But if you cannot use the Invoke method of your created delegate for some reason (because you don't know the exact delegate type, for example), you still can use the Delegate.DynamicInvoke method (however, dynamic invocation of a delegate is almost as slow as the reflection API):
Delegate del = action; // let's assume you don't know the delegate type
del.DynamicInvoke(); // slow as hell but works without throwing an exception

Manipulating the DeclaringType of a MethodInfo - Is it possible?

Basically, I have a class, let's call it 'Controller', that takes a MethodInfo as a constructor parameter. So, the class that creates this MethodInfo is called 'Descriptor'. The problem is that when 'Controller' calls the MethodInfo, it always fails with:
//MethodInfo creation on Descriptor
var mx = new Func<string>(() => "foo").Method;
//Error caused when Controller runs it
ArgumentException: Method '..anonymous...' declared on type 'Descriptor' cannot be called with instance of type 'Controller'
System.Linq.Expressions.Expression.ValidateCallInstanceType(Type instanceType, MethodInfo method)
The 'Controller' class is completely off limits for me. Do you guys have any suggestion?

Pass reflected method as parameter to another reflected method as delegate

I have a function with a signature like so
private void FunkA(string eventName, Action action) {}
private void FunkB() {}
that I obtain though reflection. The value for action is also obtained through reflection so in my code I end up having to find a way to pass a 'MethodInfo' as a parameter into an invoke.
MethodInfo miForFunkA;
MethodInfo miForFunkB;
miForFunkA.Invoke(sourceOfFunkA, new [] {
methodInfo.Name,
Delegate.CreateDelegate(typeof(Action), miForFunkB)
});
The issue is I cant create a parameter list that has string and delegate types.
How should this be passed?
You should be to specify the array type explicitly:
miForFunkA.Invoke(sourceOfFunkA, new object[] {
methodInfo.Name,
Delegate.CreateDelegate(typeof(Action), miForFunkB)
});
If that doesn't address your question, you should edit your question so that it's clearer about what you're trying to do, declarations of all variables involved, what code you have now, what it does, and how that's different from what you want to do.

Call a generic non-static method with dynamic type and generic callback as parameter

Developing an app for Android (and later iOS) using Xamarin/Mono. Normally I use this code to call a non-static generic method and it works great:
serverService.GetCustomListObject<T> (firstRequestInLine,
null,
onGetCustomListObjectFromThread<T>,
onGetCustomListObjectFromThreadError);
where the callbacks are defined as:
private void onGetCustomListObjectFromThread<T> (List<T> list,
RequestStateGen<T>.SuccessfullDelegateType successDel
{ ... }
and
private void onGetCustomListObjectFromThreadError (String error,
WebRequest failedRequest)
{ ... }
However, now I need to call GetCustomListObject<t> where t is set dynamically. I am quite new to generics but have tried the following code from other examples without success:
typeof(ServerService).GetMethod ("GetCustomListObject").MakeGenericMethod (t).Invoke (serverService, new object[] {
firstRequestInLine,
null,
typeof(LocalServerService).GetMethod ("onGetCustomListObjectFromThread").MakeGenericMethod (t),
typeof(LocalServerService).GetMethod ("onGetCustomListObjectFromThreadError")
});
where LocalServerService is the class all my examples here are in and serverService is of type ServerService
I get the following error:
Error: Ambiguous matching in method resolution
Edit: GetCustomListObject in ServerService:
public void GetCustomListObject<T> (WebRequest request,
RequestStateGen<T>.SuccessfullDelegateType successDelegate,
RequestStateGen<T>.InternalSuccessDelegateType internalSuccessDelegate,
RequestStateGen<T>.ErrorDelegateType errorDelegate)
In your original code, you were calling a method passing in delegates.
In your reflection code, you appear to be passing in MethodInfo values instead - I don't believe they will automatically be converted to delegates.
Unfortunately it's hard to give a good code sample without knowing the declaration of your GetCustomListObject method, but you want something like:
Type thirdArgType = typeof(Foo<>).MakeGenericGenericType(t);
MethodInfo thirdArgMethod = typeof(LocalServerService)
.GetMethod("onGetCustomListObjectFromThread",
BindingFlags.Instance | BindingFlags.NonPublic)
.MakeGenericMethod(t);
Delegate thirdArg = Delegate.CreateDelegate(thirdArgType, this, thirdArgMethod);
MethodInfo fourthArgMethod = typeof(LocalServerService)
.GetMethod("onGetCustomListObjectFromThreadError",
BindingFlags.Instance | BindingFlags.NonPublic);
Delegate fourthArg = Delegate.CreateDelegate(typeof(Bar), this, fourthArgMethod);
MethodInfo method = typeof(ServerService).GetMethod("GetCustomListObject")
.MakeGenericMethod (t);
method.Invoke(serverService,
new object[] {firstRequestInline, null, thirdArg, fourthArg });

Easiest way to create a delegate when the method contains a 'ref' parameter

Let's say I have this method:
public static object CallMethod(Delegate method, params object[] args)
{
//more logic
return method.DynamicInvoke(args);
}
This below has worked fine for most scenarios, calling it like so (simple example):
Delegate methodCall = new Func<decimal,decimal>(Math.Ceiling);
object callResult = CallMethod(methodCall, myNumber);
However, I've run into a situation where I need to use this on a method that takes in a 'ref' parameter (WCF service call), which the Func class can not handle.
Delegate methodCall =
new Func<MyService.InputClass, MyService.CallResult>(service.DoWork);
Since I don't have a lot of experience dealing with delegates, what would be the easiest way of creating a delegate for the above method to pass on to mine?
This isn't my application so I don't have an easy way of testing it (I was just asked if I knew of a way of resolving the problem), but does this look like it should work?
Delegate methodCall = new Func<MyService.CallResult>(delegate() { return service.DoWork(ref myInput)});
object callResult = CallMethod(methodCall, null);

Categories