control.invoke with an out parameter - c#

Winforms, C#, VS2010.
I have a polling thread that runs for the lifetime of my app.
Occasionally it calls an event on my main form. I've not touched the code for years and it's run successfully but now I need to add an "out" parameter to the list of parameters. I've searched online but all the threads I've found have been regarding reflection and been complex to attempt to convert to my context. Mine doesn't use reflection.
Can somebody help over how to fix this pls? On the reflection threads I read people seem to check some object array for the out parameter result, which I don't use in my code, and I wouldn't know where to get it anyway.
private bool OnNeedUpdateCreateEvent(string title, string message,
bool creatingNew, out string newPlanName)
{
newPlanName = "";
// 1st pass through this function.
// Check to see if this is being called from another thread rather
// than the main thread. If so then invoke is required
if (InvokeRequired)
{
// Invoke and recall this method.
return (bool)Invoke(new onNeedToUpdatePlanEvent(OnNeedUpdateCreateEvent),
title, message, creatingNew, out newPlanName); <- wrong out param
}
else
{
// 2nd pass through this function due to invoke, or invoke not required
return InputDlg(this, title, message, creatingNew, out newPlanName);
}
}

It is much like you already know, you just haven't found the array yet. It is automatically created by the compiler. The signature of the Invoke method is:
public object Invoke(
Delegate method,
params object[] args
)
It is the params keyword that gets the compiler to auto-create the array. Nice syntax sugar, but it doesn't help you here. You just have to do it yourself, like this:
if (!creatingNew) {
// Invoke and recall this method.
object[] args = new object[] { title, message, creatingNew, null };
var retval = (bool)Invoke(new onNeedToUpdatePlanEvent(OnNeedUpdateCreateEvent), args);
newPlanName = (string)args[3];
return retval;
}
// etc..

Related

Generic Delegate with dll ref/out function as Input (solved) and log it

What i got
So basically I am all over the a generic solution for a dll wrapper function to achieve logging/errorhandling easily. All my dll functions return a bool. dll is in c++
after looking at this and that that to name just a few i got to the point, that i basically do not care for the passed parameters of my dll function and all calls basically work like this:
ExecuteCommand(() => DllInterface.DllFunction([someParams]));
with
private static void ExecuteCommand(Func<bool> aCommand, string logmessage = null, bool DoThrow = true)
{
if (!aCommand())
{
if (DoThrow)
{
throw new Exception(DllInterface.LastError());
}
else
{
Log.Error(aCommand.Method.Name);
}
}
else
{
Log.Information(aCommand.Method.Name);
}
}
with that i should be able to call any function regardless of its signature.
problem is, I sometimes want to receive informations from the dll as well and therefore use ref or out.
since Func<bool> doesnt like ref i tried to do something like this:
public delegate V RefFunc<in T, U , out V>(T input, out U refType);
according to link one. this works fine as long T and V are nice types, but i couldn't found a solution, to write a lambda if Tis a Func<bool>. Test usage was implented in this way;
RefFunc<double, int, bool> refFunc = (double adouble, out int testint) =>
{
testint = (int)Math.Truncate(adouble);
return true;
};
Reffunc(adouble, out int aInt);
what i wanted (and already got)
is basically a overload of Execute command which accepts
ExecuteCommand(() = > DllInterface.DllFunctions(ref int rval));
and actually executes
...if(!acCommand(ref rval) ...
is this possible?
Answer
The Answer was already there, as it turns out I can pass any functions to the current ExecuteCommand(), since the signature passed as a command is defined by the Lambda, not the function the Lambda is calling.

TargetException on Invoke

I have a problem with my Invoke() throwing a TargetException.
public Controller(SystemUI ui, System system)
{
UI = ui;
System = system;
UI.CommandEntered += ParseCommand;
Commands = new Dictionary<string, Delegate>();
Commands.Add(":q", new Action(UI.Close));
}
I then call Commands[input[0]].Method.Invoke(this, input.ToArray<object>());, but it throws a TargetException with the message
Object does not match target type.
Do I need a cast?
I'm quite lost, and I'd appreciate any help!
Based on comments above, you are trying to invoke an Action (UI.Close), but you are passing an array of objects as parameters to this action, which has no parameters therefore incurring this exception.
Change...
input.toArray<object>()
to...
new object[0], or new object[] {} // or perhaps even just null may do the trick.

Getting The Method That A Method Was Called From? [duplicate]

This question already has answers here:
How can I find the method that called the current method?
(17 answers)
Closed 6 years ago.
Is it possible to determine the calling method name "Eat Pizza" in PostError?
I guess I could pass "EatPizza" as one of the arguments, but that would require changes each time the method name changes (unnecessary maintenance). But then, I wasn't even able to find the method name "EatPizza" in the context of "EatPizza" (using stacktrace, getframe, getmethod).
public void EatPizza(Pizza p){
if(p==null){ //A arbitrary made up error
Utilities.PostError();
}
else{
p.Slices -= 1;
}
}
...
public void PostError(){
//Basically posting to database the name of the method
//Tried this, didn't work: (new StackTrace(true)).GetFrame(5).GetMethod().Name
//Is it possible to determine the calling method name "Eat Pizza" in this context?
}
When I try different values (0 to StackTrace.FrameCount-1) in StackTrace.GetFrame, I get the following values, when I just want "EatPizza":
.ctor
ThreadStart
Main
_nExecuteAssembly
RunUsersAssemblyDebugInZone
You were on the right track with creating a StackTrace object, but you seem to have misunderstood the argument to GetFrame. Frames are numbered from the bottom-most frame, so:
GetFrame(0) would return PostError
GetFrame(1) would return the caller of PostError
So just try this:
var trace = new StackTrace(true);
WriteToDB(trace.GetFrame(1).GetMethod().Name);
Personally, I would prefer to get the entire stack trace rather than just the caller, so I'd do this:
var trace = new StackTrace(true);
WriteToDB(trace.ToString());
Is it possible to determine the calling method name "Eat Pizza" in PostError? I guess I could pass "EatPizza" as one of the arguments, but that would require changes each time the method name changes (unnecessary maintenance).
Calling PostError in all the methods in which something could go wrong is also "unnecessary maintenance". It also complicates the execution flow of your program, because you will have to check for errors all over the place, and high-level processes will have to check if the low level processes completed successfully.
It is better to use the exception handling structures provided by the CLR and C#.
The exact location in which the error occured is stored in the exception's StackTrace property.
pubic void BigDinnerEatingProcess()
{
try
{
WhateverHappensAtTheTopLevel();
}
catch (PizzaNotDeliveredException ex)
{
Utilities.PostError(ex);
MessageBox.Show("Dinner was not eaten. Please make sure the pizza is delivered.");
}
}
public void EatPizza(Pizza p)
{
if (p == null)
throw new PizzaNotDeliveredException();
p.RemoveOneSlice();
}
private void PostError(Exception ex)
{
string errorLocation = ex.StackTrace;
//...
}

C# parameter count mismatch when trying to add AsyncCallback into BeginInvoke()

I have main form (PrenosForm) and I am trying to run Form2 asynchronously.
It works without callback delegate:
this.BeginInvoke(cp, new object[] { datoteke, this.treeView1.SelectedNode.FullPath.ToString(), this, efekt }, null); //works 1.
Doesn't work with callback delegate (parameter count mismatch):
this.BeginInvoke(cp, new object[] { datoteke, this.treeView1.SelectedNode.FullPath.ToString(), this, efekt }, new AsyncCallback(callBackDelegate), null); //doesn't work parameter count mismatch 2.
Works with callback delegate if I do it like this:
cp.BeginInvoke(datoteke, this.treeView1.SelectedNode.FullPath.ToString(), this, efekt, new AsyncCallback(callBackDelegate), null); //works 3.
My question is why does one way work and the other doesn't? I'm new at this. Would anyone be so kind as to answer my question and point out my mistakes?
private delegate void copyDelegat(List<ListViewItem> datoteke, string path, PrenosForm forma, DragDropEffects efekt);
private delegate void callBackDelegat(IAsyncResult a);
public void doCopy(List<ListViewItem> datoteke, string path, PrenosForm forma, DragDropEffects efekt)
{
new Form2(datoteke, path, forma, efekt);
}
public void callBackFunc(IAsyncResult a)
{
AsyncResult res = a.AsyncState as AsyncResult;
copyDelegat delegat = res.AsyncDelegate as copyDelegat;
delegat.EndInvoke(a);
}
public void kopiraj(List<ListViewItem> datoteke, DragDropEffects efekt)
{
copyDelegat cp = new copyDelegat(doCopy);
callBackDelegat callBackDelegate = new callBackDelegat(callBackFunc);
this.BeginInvoke(cp, new object[] { datoteke, this.treeView1.SelectedNode.FullPath.ToString(), this, efekt }, new AsyncCallback(callBackDelegate), null); //doesn't work parameter count missmatch 2.
this.BeginInvoke(cp, new object[] { datoteke, this.treeView1.SelectedNode.FullPath.ToString(), this, efekt }, null); //works 1.
cp.BeginInvoke(datoteke, this.treeView1.SelectedNode.FullPath.ToString(), this, efekt, new AsyncCallback(callBackDelegate), null); //works 3.
}
It is because Control.BeginInvoke() has a completely different signature from SomeDelegate.BeginInvoke(). While their method names are the same, they are fundamentally different methods. And fundamentally work differently at runtime, there is no comparison.
Control.BeginInvoke() takes a delegate and an object[]. Cast in stone.
private delegate SomeDelegate(mumble, foo, bar) automatically creates a SomeDelegate.BeginInvoke() method. Whose signature takes those three arguments, plus two extra arguments, a callback and a state object.
A significant runtime difference is that Control.BeginInvoke() can call a delegate and if it bombs with an exception then the exception is raised on the UI thread. A delegate's BeginInvoke() method doesn't do this, it re-raises the exception in the callback that calls EndInvoke().
Very confuzzling, I know, maybe they shouldn't have used the same name.
Don't do this at all.
Showing multiple forms on different threads is an extremely bad idea and will end up causing lots of trouble.
Your second example doesn't work because Control.BeginInvoke doesn't support a callback parameter.
Your code is interpreted as calling a delegate with three parameters; an array, and AsyncCallback, and null.
Since your method doesn't take such parameters, an exception is thrown.
Also, calling Control.BeginInvoke won't run a function in the background; it will run it on the UI thread when it next reaches the message loop.

C# Is there a way to create functions that accept anonymous function code as argument?

I would like to do something like
NameOfTheMethod(parameters){
// Code...
}
There's using, foreach, for, etc. that are already built-in, but I don't know if creating something similar is even possible. Is it?
The reason why I ask this is because sometimes that there are many different pieces of code that are wrapped by basically the same code (examples are opening a connection to the database, creating the command, settings the datareader, testing if an element exists in cache and, if not, go get it, otherwise get it from cache, etc.)
Yes, you can take a delegate instance as an argument:
void MyMethod(Func<Arg1Type, Arg2Type, ReturnType> worker) {
Arg1Type val1 = something;
Arg2Type val2 = somethingelse;
ReturnType retVal = worker(something, somethingelse);
// ...
}
You'd call it like:
MyMethod((arg1, arg2) => {
// do something here with the arguments
return result;
});

Categories

Resources