storing/passing delegates as variables - c#

I am fairly new to C# and was working on a a way to implement a dynamic GUI which uses the serial communication. I originally come from C, so the concept of function pointer is familiar.
Basically I want to invoke a answerFunction() function when the serial command has been processed.
In Theory:
I have a Class lbl_txtBox_Pair which is dynamically created on runtime.
I have a Class comObject which communicates with the serial Port.
I have a third class comPacket which holds all information regarding one serial command.
in an Object of Class lbl_txtBox_Pair I instantiate a Packet and tell it which function should be called when the serial command is finished.
I give the packet Object to the comObject Instance.
after being processed the comObject wants to signal the original sender of the packet by calling the delegate which is stored in the Packet Object.
For some reason I can't get it to work. It tells me that the Attribute of Packet is not callable. Am I doing something terribly wrong?
Here is the Code:
first the code in Class "lbl_txtBox_Pair". I create the comPacket here and give it to the comObject.
public delegate void answerHandler( comPacket packet);
public void txb_value_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Return)
{
answerHandler answerMethod = new answerHandler(this.processAnswer);
comPacket question = new comPacket(this.command, answerMethod, 1);
comObject.addPacket(question);
}
}
The constructor of comPacket. Here the delegate gets stored to be called later.
public Delegate answerFunction;
public comPacket(string cmd, Delegate func, int prio)
{
this.cmd = cmd;
answerFunction = func;
this.prio = prio;
}
In the comObject the Packets get processed. When finished I want to call the function stored in the Packet. The comObject runs in a different Thread by the way.
if (this.isEndtocken(inputline))
{
listen = false;
packet.answerFunction(packet);
}
And here it is were it breaks. packet.answerFunction(packet); wont execute and says it can't be called as Method.
Can anybody see where it goes wrong? I think it seems like the delegate looses the information that it is a delegate or something.
Or do I have to completely restructure the code to use other types of callback / Event Methods?

Change your comPacket to take a strongly typed delegate:
public answerHandler answerFunction;
public comPacket(string cmd, answerHandler func, int prio)
{
this.cmd = cmd;
answerFunction = func;
this.prio = prio;
}
If you still want to keep the delegate reference weakly typed, you can leverage DynamicInvoke instead: http://msdn.microsoft.com/en-us/library/system.delegate.dynamicinvoke.aspx
EDIT: Another option if you want to maintain strongly typed delegates yet have different usages is to leverage generics. Your delegate can be housed in a generic class and tie its signature against that generic type.

I can't leave a comment so I have to post this as an answer instead.
Delegates (and events and stuff) can usually only be "invoked" by the object that contains them.
So if you have
class MyClass {
public event Action someEvent;
// you can also replace Action with the name of your delegate type
}
and you try to do
MyClass x = new MyClass();
x.someEvent.Invoke();
Then that's an error. If you want other objects to be able to invoke the event, you'll have do add a method to MyClass like this:
public void InvokeMyEvent() {
someEvent.Invoke();
}
(I forget whether you still have to do this for static events)

Related

Action Delegation in C#

I am reviewing some code from a sample application for an API, and need some help better understanding the Action<T> delegation throughout the sample app. I have put several questions throughout the code. Any help is appreciated
The API is implemented in the Client.cs class, and when I make requests from the application, the API sends the responses to the functions in Client.cs that have been implemented.
/***** Client.cs *****/
public event Action<int, int, int> TickSize;
void tickSize(int tickerId, int field, int size)
{
var tmp = TickSize;
//What is the point of tmp, and why do we check if it is not null?
if (tmp != null)
//This invokes the Action? ie - fires the TickSize Action event?
tmp(tickerId, field, size);
}
Then the UI.cs class handles the UI interactions and feeding the information back into the UI so the user can see what data is returned
/***** UI.cs *****/
//Delegate to handle reading messages
delegate void MessageHandlerDelegate(Message message);
protected Client client;
public appDialog(){
InitializeComponent();
client = new Client();
.
.
//Subscribes the client_TickSize method to the client.TickSize action?
client.TickSize += client_TickSize;
}
void client_TickSize(int tickerId, int field, int size){
HandleMessage(new Message(ticketID, field, size));
}
public void HandleMessage(Message message){
//So, this.InvokeRequired checks if there is another thread accessing the method?
//Unclear as to what this does and its purpose
//What is the purpose of the MessageHandlerDelegate callback
// - some clarification on what is going on here would be helpful
if (this.InvokeRequired)
{
MessageHandlerDelegate callback = new MessageHandlerDelegate(HandleMessage);
this.Invoke(callback, new object[] { message });
}
else
{
UpdateUI(message);
}
}
private void UpdateUI(Message message) { handle messages }
From the docs
Events are a special kind of multicast delegate that can only be invoked from within the class or struct where they are declared (the publisher class). If other classes or structs subscribe to the event, their event handler methods will be called when the publisher class raises the event
So in Client.cs you have a multicast delegate called TickSize. This delegate enables other classes to subscribe to the event it is associated with. So in your function void tickSize(int tickerId, int field, int size), you want to let all the other subscribers know that a tick event has happened.
To do this, you first see if you have any subscribers. This is where the null check happens in if (tmp != null). Having tmp is not needed, you could have done if(TickSize != null) If you have any eventhandlers registered, it would fire and subscribers will receive that call. In your case, you do have subscribers because you are subscribing to the event in public AppDialog with this code : client.TickSize += client_TickSize;
So whenever void tickSize(...) is called in Client.cs, the code in void client_TickSize(...) will run. This will call HandleMessage which will check if it needs to be called by an Invoke function because calling code is not on UI thread. If it does need to be called using Invoke, it will then call the same message using current Control's Invoke function (Not sure which control, could be Form). The HandleMessage will then see that Invoke is not required because caller is on UI thread and then it will call UpdateUi which will update controls.

Calling functions one after other in event driven programming

I'm working on a software where software issues commands for hardware panel and once a command is issued, its response received after few seconds . there are different functions for different hardware commands like
public void FunctionA()
{
StartCommandA();
}
and other functions on the same pattern that will be used to run other commands.
FunctionB();
FunctionC();
Once we receive the response of command A , I invoke the other function from the response but this approach is not good as per design pattern practices.
All i want to do is to make a list of functions and invoke all these functions one after other, But next function will be called once i get response of first functions.
I tried this by using Multicast delegate but I'm unable to find out how we can call get the list of functions once i add all functions to that delegates. This is what i'm trying do since.
FunList funList_ConfigAndSerialTests = new FunList(StartSerialTest);
funList_ConfigAndSerialTests += StartSerialTest;
funList_ConfigAndSerialTests += StartMsrTest;
funList_ConfigAndSerialTests += StartContactLessTest;
//funList_ConfigAndSerialTests.Invoke();
Delegate[] del = funList_ConfigAndSerialTests.GetInvocationList();
foreach (Delegate item in funList_ConfigAndSerialTests.GetInvocationList())
{
while (true)
{
if (IsResponseReceived == true)
{
// Call function here
}
}
}
The simplest way to do this is to call the functions one by one:
FunctionA();
FunctionB();
FunctionC();
Each method will be called only after the previous has returned.
But you said you want to call the next function after the previous one has a response. Now that sounds like your functions run asynchronously. I strongly suggest you use the async keyword to mark your functions and make them return a Task<ResonseType>. You can learn about this here.
You'll then be able to do something like this:
await FunctionA(); // you obviously want to do something with the returned response
// I do not know your requirements so I did not show that part
await FunctionB();
await FunctionC();
It seems what you're trying to achieve is what Events are for. In the class, where the handlers (FunctionA, FunctionB, ...) are defined create an event instance as follows:
public class MyClass
{
private event Action Event;
public void RegisterHandlers()
{
Event += FuncA;
Event += FuncB;
Event();
}
public void HandleCommand()
{
this.Event();
}
private void FuncA() { /*...*/ }
private void FuncB() { /*...*/ }
}
The simple call to Events() will actually result in all the registered handlers to be invoked in the order they've been registered.

Passing Actions into generic functions

I'm trying to wrap my head around different concepts in Csharp by trying different things. A create a generic function that takes in an action. The action has one input parameter and returns void. I create a simple action that is linked to a lambda function (returns void has one parameter x). I am able to run the action but when I pass the function to my generic function I am not sure how to add the input parameter. act("Some Int") doesn't work.
How do I pass in a value to an action?
public MainWindow()
{
InitializeComponent();
Action<int> myAction = (x) => Console.WriteLine(x);
myAction(13);
test(myAction);
}
private static void test<T>(Action<T> act)
{
act(); // How do i pass in an int Here?
}
Simply calling act("Some Int") as you have just required the Action act to be a genric function. Therefore you cannot specifically invoke it with one fixed variable type. You can solve your problem by modifying the test-method
private static void test<T>(Action<T> act, T value)
{
act(value); // How do i pass in an int Here?
}
...
test(myAction,integerValue);
Now you can call the Action with a given intvalue.
I can see what you are trying to do, and just wanted to throw this pattern up, since we often do this when we have to use closures and the parameters could be wildly different.
In those cases, rather than define an Action<T> which kind of ties you down from being able to use closures, you would just simply define your method as Action. So test would look like this:
private static void test(Action act)
{
act(); // yup, that's all there is to it!
}
So how would you pass in the parameter(s)? Simple: use closures. Like this:
public MainWindow()
{
InitializeComponent();
var x = 13; // this defined outside now...
Action myAction = () => Console.WriteLine(x); // you're basically using the closure here.
myAction();
test(myAction);
}
We often use this sort of approach when we're context switching (aka thread jumping), and need the thread continuation to pick up one or more variable values at the point it executes. That's just one example, there's quite a few other valid use cases as well.
Your experimental example, if I'm reading it correctly, could also qualify as a situation where closures could be a good fit.

Generic BeginInvoke Scheme to ensure function calls in same threading context

I'm moving some code from a winforms control object to a separate object for better modularity. However, there some calls to an external object issuing callbacks, which I have no control of and which can be fired from different threads as the main UI thread. To avoid this I use the well known BeginInvoke scheme to check, whether a call should be transfered to the main UI thread.
When I now move this code to my separated object, I have not necessary a Winforms reference anymore. I could handle over a Control object to still ensure that everything is running in the same thread. But I would rather like to have a generic mechanism which does exactly the same like ensuring, that the Threadconext in which the e.g. the object was created or a specific entry function was called is also used for subsequent calls issued e.g. by external callbacks.
How could this achieved most easily ?
Example:
public class Example
{
ThreadedComponent _Cmp = new ThreadedComponent();
public Example()
{
_Cmp.ThreadedCallback += new ThreadedComponent.CB(Callback);
}
public void StartFunction()
{
// called in ThreadContextA
_Cmp.Start();
}
void Callback(Status s)
{
// is called in ThreadContextB
if(s == SomeStatus)
_Cmp.ContinueFunction(); // must be called in ThreadContextA
}
}
For clarification
ContinueFunction must be called from the same ThreadContext like StartFunction was called. This is not necessarily a UI thread, but at the moment it is of course a button handler.
There is no 'generic' scheme, your class cannot make a lot of assumptions about what thread it is used on and what object can provide the BeginInvoke() method you need. Choose from one of the following options:
Do not help at all, simply document that the event can be raised on a worker thread. Whatever code exists in the GUI layer can of course always figure out how to use BeginInvoke() when needed.
Allow the client code to pass a Control object through your class constructor. You can store it and call its BeginInvoke() method. That works, it isn't terribly pretty because your class now is only usable in a Winforms project.
Expose a property called "SynchronizingObject" of type ISynchronizeInvoke. The GUI layer now has the option to ask you to call ISynchronizeInvoke.BeginInvoke(). Which you do if the property was set, just fire the event directly otherwise. Several .NET Framework classes do this, like Process, FileSystemWatcher, EventLog, etc. It however has the same problem as the previous solution, the interface isn't readily available in a non-Winforms application.
Demand that the client code creates your object on the UI thread. And copy SynchronizationContext.Current in your constructor. You can, later, use its Post() method to invoke. This is the most compatible option, all GUI class libraries in .NET provide a value for this property.
Do keep the trouble in mind when you choose one of the latter bullets. The client code will get the event completely unsynchronized from your thread's code execution. A concrete event handler is somewhat likely to want to access properties on your class to find out more about the state of your class. That state is unlikely to still be valid since your thread has progressed well past the BeginInvoke() call. The client code has no option at all to insert a lock to prevent that from causing trouble. You should strongly consider to not help at all if that's a real issue, it often is.
In C# you cannot assign a thread context to an object, like in Qt for example (C++).
A thread is running in itself, it does not "collect" objects or methods to call them if they were marked somehow.
However synchronizing to a GUI thread in C# is very easy. Instead of the BeginInvoke/Invoke pattern, you can create a System.Windows.Forms.Timer instance, which can call the methods on the non-WinForms objects.
Example:
public interface IMyExternalTask
{
void DoSomething();
}
// ...
List<IMyExternalTask> myTasks = new List<IMyExternalTask>();
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Interval = 1000; // Call it every second
t.Tick += delegate(object sender, EventArgs e) {
foreach (var myTask in myTasks)
myTask.DoSomething();
};
t.Start();
In the example your "external" objects must implement the interface, and they can do their tasks from the DoSomething() method, which will be synchronized to the GUI thread.
These external objects don't have to have any reference to any Windows.Forms object.
I solve the problem using a separate queue which runs its own thread. Function Calls are added to the Queue with a Proxyinterface. It's probably not the most elegant way, but it ensures, that everything added to the queue is executed in the queue's threadcontext. This is a very primitive implementation example just to show the basic idea:
public class Example
{
ThreadQueue _QA = new ThreadQueue();
ThreadedComponent _Cmp = new ThreadedComponent();
public Example()
{
_Cmp.ThreadedCallback += new ThreadedComponent.CB(Callback);
_QA.Start();
}
public void StartFunction()
{
_QA.Enqueue(AT.Start, _Cmp);
}
void Callback(Status s)
{
// is called in ThreadContextB
if(s == SomeStatus)
_QA.Enqueue(new ThreadCompAction(AT.Continue, _Cmp);
}
}
public class ThreadQueue
{
public Queue<IThreadAction> _qActions = new Queue<IThreadAction>();
public Enqueue(IThreadAction a)
{
lock(_qActions)
_qActions.Enqueue(a);
}
public void Start()
{
_thWatchLoop = new Thread(new ThreadStart(ThreadWatchLoop));
_thWatchLoop.Start();
}
void ThreadWatchLoop()
{
// ThreadContext C
while(!bExitLoop)
{
lock (_qActions)
{
while(_qActions.Count > 0)
{
IThreadAction a = _qActions.Dequeue();
a.Execute();
}
}
}
}
}
public class ThreadCmpAction : IThreadAction
{
ThreadedComponent _Inst;
ActionType _AT;
ThreadCmpAction(ActionType AT, ThreadedComponent _Inst)
{
_Inst = Inst;
_AT = AT;
}
void Do()
{
switch(AT)
{
case AT.Start:
_Inst.Start();
case AT.Continue:
_Inst.ContinueFunction;
}
}
}

C# Delegates and Events logic and syntax issues

As my code suggests, I'm trying to create a delegate which will point to the StringBuff method BuffString, which creates a StringBuilder that is going to have a fair amount of settings, etc.
My problem is that, for some reason, no matter what it is I try I can't pass the reference to the StringBuff class I made within my Sprite class to the delegate's constructor without receiving an error. Ontop of that, I feel like creating an event may be useful to help initiate the delegate.
The main problem is that I'm just now barely grasping these two concepts, as well as how to use them as replacements for function pointers which are allowed in other programming languages.
If anyone has any idea on what it is I need to do to make this work, I would definitely appreciate it.
Here's the code:
public class StringBuff
{
private static StringBuilder stringBuffer = new StringBuilder();
public static StringBuilder BuffString(string _string) //--may possibly have to use IntPtr to reference stringBuffer here.
//This is the equivalent to the "strbuff_new" C++ method variant, designed to update the stringBuffer.
{
int iCounter = 0;
stringBuffer.Append(_string + " ");
iCounter += _string.Length + 1;
if (iCounter == stringBuffer.Capacity - 1)
{
stringBuffer.Capacity += stringBuffer.Capacity;
}
return stringBuffer;
}
}
public delegate void UpdateStringBuffer(StringBuff sender);
public class Sprite : SpriteInterface.ISprite
{
private StringBuff stringBuff = new StringBuff();
public event UpdateStringBuffer stringBuffEvent
{
add
{
Console.WriteLine("Adding");
stringBuffEvent += value;
}
remove
{
Console.WriteLine("Removing...");
stringBuffEvent -= value;
}
}
static void Main()
{
new Sprite().stringBuffEvent += new UpdateStringBuffer(stringBuff);
}
}
I believe you are in need for some reading. Refer to the following:
Events Tutorial
Introduction to Delegates and Events
Events and Delegates simplified
You are misunderstanding the use of events and delegate.
When you want to add an Event Handler to an event, you pass a delegate of the same type as the event (which you did correctly)
But when you create a delegate, what you should pass in the constructor (most of the time) is a Method Name and not some variable, since a delegate is a kind of pointer to a (list of) functions.
I reccomend you to read more about delegates as Akram Shahda suggested but just for now i'll tell you that the method that you should pass as parameter to the delegate constructor should have the same signature - means return the same value and accept the same parameters. so for example you could have:
// This method have the same signature as UpdateStringBufferDelegate
public void SomeMethod (StringBuff buff)
{
// Doing somthing here
}
And then you can do in your main:
// Passing method's name and not a variable!!
new Sprite().stringBuffEvent += new UpdateStringBuffer(SomeMethod);
The Actuall parameters that will be passed to the function itself (some StringBuff) only determined at the time of the invokation of the event.
You should read more about that.
Good Luck!
you are doing it wrong,
new Sprite().stringBuffEvent += new UpdateStringBuffer(stringBuff);
Above code is invalid due to following reasons.
1. stringBuff that your UpdateStringBuffer is taking is an instance of StringBuff within Sprite.
2. You are accessing stringBuff from the static Main method which does not have any idea about stringBuff where it is located.
1- The delegate's constructor can only have a parameter Method. Ex
public delegate void UpdateStringBuffer(StringBuff sender);
2- You can declare ur event and add a method to define ur method in ur Splite class. Ex:
public event UpdateStringBuffer stringBuffEvent;
public ProcessUpdateStringBuffer(UpdateStringBuffer yourMethod)
{
stringBuffEvent += yourMethod
}
3- and from ur main u can define ur method to the event and invoke it like this:
Sprite sprite = new Sprite();
sprite.ProcessUpdateStringBuffer(UpdateStringBuffer(urMethod));
sprite.stringBuffEvent(ur parameters);

Categories