C# DynamicInvoke TargetParameterCountException - c#

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?

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

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.

Pattern to reuse logic regardless of number of parms

I have some logging logic I want to call before and after several methods. Each method accepts different number/type of parameters. I'm trying to set it up so I don't have to duplicate the logging logic when I call each method. I've been able to reduce the amount of duplication by creating some delegates. I've created a delegate for each number/type of parms used and I have a method that accepts each delegate and does the logging. However, I still have around 6 different delegates and so the logic is duplicated for those six.
I think there is away to modify this so regardless of the number of parms, I have one method that does the logging and calls the method. But I haven't been able to figure it out.
Below is an example of one of the delegates and the logic I'm trying not to duplicate.
public delegate void LineOfBusinessHandler(DateTime runDate, LineOfBusinessCode lineOfBusinessCode);
public void Run(DateTime runDate, ProcessCode process, LineOfBusinessCode lineOfBusinessCode, LineOfBusinessHandler del)
{
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Started.ToString(), null, runDate);
try
{
del(runDate, lineOfBusinessCode);
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Finished.ToString(), null, runDate);
}
catch (Exception e)
{
int errorId = SystemManager.LogError(e, process.ToString());
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Errored.ToString(), errorId, runDate);
}
}
I realize this maybe beyond the scope and/or the capabilities of what you're looking for. But if you have a generic logging logic that you want to reuse over different method calls, without losing typesafety (i.e. NOT passing your arguments around in object[]) the way to go is interception. You need a framework (I don't recommend writing your own at first!) that can provide AOP, Dependency Injection or something similiar. Those things can usually deal with interception.
For example I have a logging interceptor I use with Ninject:
public void Intercept(IInvocation invocation)
{
var logger = LoggerFactory.GetLogger(invocation.Request.Method.DeclaringType);
var debug = !invocation.Request.Method.IsSpecialName && logger.IsDebugEnabled;
if (debug)
logger.Debug(invocation.Request.Method.Name);
try
{
invocation.Proceed();
if (debug)
logger.Debug(invocation.Request.Method.Name + " FINISH");
}
catch (Exception)
{
logger.Error(invocation.Request.Method.Name + " ERROR");
throw;
}
}
Then I create my objects by getting them with Ninject (if you don't know about it, check out some tutorials), while adding some Interception to them, for example: Kernel.Bind<MyTypeToLog>().ToSelf().Intercept().With<LoggingInterceptor>(); where LoggingInterceptor implements IInterceptor with the method shown above...
Just say if you need more in details help!
EDIT: just realized that my example doesn't show this, but you can access the arguments (as an object collection though) of the invocation too!!
It depends on what is common among the different versions, but assuming runDate and process are common you could do something like this:
public void Run(DateTime runDate, ProcessCode process, LineOfBusinessCode lineOfBusinessCode, LineOfBusinessHandler del)
{
this.DoRun(runDate, process, (d, p) => del(d, p, lineOfBusinessCode));
}
public void DoRun(DateTime runDate, ProcessCode process, Action<DateTime, ProcessCode> action)
{
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Started.ToString(), null, runDate);
try
{
action(runDate, process);
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Finished.ToString(), null, runDate);
}
catch (Exception e)
{
int errorId = SystemManager.LogError(e, process.ToString());
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Errored.ToString(), errorId, runDate);
}
}
You can even generalize so you don't have do define custom delegates as this:
public void Run<T1>(DateTime runDate, ProcessCode process, T1 param1, Action<DateTime, ProcessCode, T1> del)
{
this.DoRun(runDate, process, (d, p) => del(d, p, param1));
}
public void Run<T1, T2>(DateTime runDate, ProcessCode process, T1 param1, T2 param2, Action<DateTime, ProcessCode, T1, T2> del)
{
this.DoRun(runDate, process, (d, p) => del(d, p, param1, param2));
}
The C# language doesn't have any syntax for metaprogramming. You'll have to use reflection. You certainly can reflect against an arbitrary method/delegate to determine the parameter types, then build a method that logs parameters and calls the original method, compile this new wrapper method, and return a delegate with the same call signature as the original.
You can do this at runtime (return a delegate) or build a new assembly with all the wrapper functions, that can then be referenced by your code and used normally.
You should look at the code-weaving tools used for Aspect-Oriented-Programming. Some of them already do this.
Unlike using a params array, this gives you a wrapper with the same signature (or delegate type) as the original method, so it is type safe and Intellisense works (as much as for any other delegate).
If I understand your question correctly it sounds like you could use the C# params keyword. See this for a reference on how to use it: http://msdn.microsoft.com/en-us/library/w5zay9db.aspx
One of the requirements when using params is that it has to be placed last in the signature of the function. Then, inside of the function you can enumerate and iterate over the variable parameters list as if it were an array.
EDIT
To expand on a comment posted by #Ben Voigt, another limitation of using the params keyword is that it requires the variable parameter list to be of the same type. This however can be mitigated in your case since all you care about is logging. In this case presumably you would be invoking the ToString() method on the objects you need to log so you could make the variable parameters list of type object.
In case calling the ToString() is not enough and you have different types of objects you could make all these objects implement a common interface. Let's call it ILoggableObject which exposes a method to provide the logging output. That's if you have the ability to change those objects.

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

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