Pass reflected method as parameter to another reflected method as delegate - c#

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.

Related

TargetParameterCountException: Parameter count mismatch on invoke - delegate

I have the following code (removed unrelated)
//top of class declaration
private delegate void UpdateFormElements(string status, bool addEmptyRow);
//inside a function in my class
if(lboImages.InvokeRequired)
{
lboImages.Invoke((UpdateFormElements)delegate { UpdateListBox("some text", true); });
}
private void UpdateListBox(string line, bool addEmptyRow)
{
lboImages.Items.Add(line);
if (addEmptyRow)
{
lboImages.Items.Add("");
}
}
Basically I'm trying to pass two parameters to the UpdateListBox function to test whether to add an empty line or not to my listbox, but I am getting the error in the title. I have tried putting the two values in an object[] but it doesn't seem to change anything as I still get the error.
I'm still new to using threads so not really sure where I'm going wrong here.
It's not clear why you're trying to use an anonymous method here. The problem is that you're creating a delegate type with two parameters, but you're not passing arguments (values for those parameters) into Invoke.
I suspect you just want:
lboImages.Invoke((UpdateFormElements) UpdateListBox, "some text", true));
That uses a method group conversion to create an UpdateFormElements delegate, and provides it the two arguments it needs.
Alternatively, you could just use a lambda expression:
MethodInvoker invoker = () => UpdateListBox(line, addEmptyRow);
lboImages.Invoke(invoker);

C# DynamicInvoke TargetParameterCountException

i've been searching a while now but i haven't found a solution for my Problem. I've got a class that stacks methods on a list and then calls them one by one.
Everything works fine with return values, Parameters or methods without Parameters. But if a method has a optional Parameter it doesn't work.
This is just a simple testing method:
static void TestMe(Int32 _wait = 5000)
{
//Pretend to do stuff...
System.Threading.Thread.Sleep(_wait);
}
I add the method to my stack with:
static StackHandler __handler = new StackHandler();
__handler.AddMethod(new Action<Int32>(TestMe));
The AddMethod method creates a new ListItem and adds it into an internal list to Keep track of all stacked methods.
Then the handler wants to call the method with:
private object invokeMethod(Delegate _method, params object[] _args)
{
return _method.DynamicInvoke(_args);
}
I get a System.Reflection.TargetParameterCountException in the invokeMethod method. I've also tried to call it without the args Parameter, same result.
If i add the method TestMe like this:
__handler.AddMethodAsync(new Action<Int32>(Method), 6000);
It just runs fine.
How can i get this to work with optional Parameters?

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);

How to call a MethodInfo?

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.

C# compiler oddity with delegate constructors

Based on the following question, I found some odd behaviour of the c# compiler.
The following is valid C#:
static void K() {}
static void Main()
{
var k = new Action(new Action(new Action(K))));
}
What I do find strange is the compiler 'deconstructing' the passed delegate.
The ILSpy output is as follows:
new Action(new Action(new Action(null, ldftn(K)), ldftn(Invoke)).Invoke);
As one can see, it automatically decides to use the Invoke method of the delegate. But why?
As it is, the code is unclear. Do we have a triply-wrapped delegate (actual) or is the inner delegate just 'copied' to the outer ones (my initial thought).
Surely if the intent was like the compiler emitted the code, one should have written:
var k = new Action(new Action(new Action(K).Invoke).Invoke);
Similar to the decompiled code.
Can anyone justify the reason for this 'surprising' transformation?
Update:
I can only think of one possible use-case for this; delegate type conversion. Eg:
delegate void Baz();
delegate void Bar();
...
var k = new Baz(new Bar( new Action (K)));
Perhaps the compiler should emit a warning if the same delegate types are used.
The spec (section 7.6.10.5) says:
The new delegate instance is initialized with the same invocation list as the delegate instance given by E.
Now suppose the compiler translated it to something similar to your suggestion of:
new Action( a.Target, a.Method)
That would only ever create a delegate with an invocation list of a single method call. For a multi-cast delegate, it would violate the spec.
Sample code:
using System;
class Program
{
static void Main(string[] args)
{
Action first = () => Console.WriteLine("First");
Action second = () => Console.WriteLine("Second");
Action both = first + second;
Action wrapped1 =
(Action) Delegate.CreateDelegate(typeof(Action),
both.Target, both.Method);
Action wrapped2 = new Action(both);
Console.WriteLine("Calling wrapped1:");
wrapped1();
Console.WriteLine("Calling wrapped2:");
wrapped2();
}
}
Output:
Calling wrapped1:
Second
Calling wrapped2:
First
Second
As you can see, the real behaviour of the compiler matches the spec - your suggested behaviour doesn't.
This is partly due to the somewhat odd "sometimes single-cast, sometimes multi-cast" nature of Delegate, of course...
When you try to treat a delegate as a method, the compiler actually uses the delegate's Invoke() method. So, for example, the two lines below compile to the exact same IL (both call Invoke()):
k();
k.Invoke();
I assume the oddity you're seeing is a consequence of this. The delegate constructor expects a method (or rather, a method group), but it gets a delegate instead. So it treats it as a method and uses the Invoke() method.
As for the meaning, it is delegate that calls delegate that calls the actual method. You can verify this yourself by accessing the delegate's Method and Target properties. In the case of the outer-most delegate, Method is Action.Invoke and Target the inner delegate.
delegate is a class
Action delegate has a constructor like so
public extern Action(object #object, IntPtr method);
Since K is a static method there is no need to pass object to inner most action instance as first argument and hence it passes null
Since second argument is pointer to function therefore it passes pointer of K method using ldftn function
for the remaining Action instances the object is passed is inner Action and the second parameter is the Invoke method since when you call a delegate you're actually calling the Invoke method
Summary
var action = new Action(K) => Action action = new Action(null, ldftn(K))
new Action(action) => new Action(action, ldftn(Action.Invoke))
I hope this explains what is happening?

Categories