C# has to subscribe to an event before event called - c#

I want to implement a fast way to add listener to an event, my implementation:
public class AccountManager
{
public delegate void CheckIfLoggedInListener(EventArgs e);
public event CheckIfLoggedInListener SetCheckIfLoggedInListener;
public void CheckIfLoggedIn()
{
if(SetCheckIfLoggedInListener!=null)
SetCheckIfLoggedInListener(new EventArgs("e"));
}
}
Right now, I have to set listener first, then invoke the method, which can be easily messed up if other developer doesn't pay attention:
//this will not work, because you invoke the event before subscribing
accountManager.CheckIfLoggedIn();
accountManager.SetCheckIfLoggedInListener += (e) => { Debug.Log(e.param); };
I wonder if there is a way to make the order not mandatory?

You can take a parameter of generic delegate that will be object of type Action<T> and in your case it would beAction<EventArgs> in your method to make sure that:
EDIT:
you would need to tweak it to work, instead of Action<EventArgs>, we would have to use Action<Object,EventArgs>, this post explains why is that
public void CheckIfLoggedIn(Action<object,EventArgs> action)
{
SetCheckIfLoggedInListener = action.Invoke;
if(SetCheckIfLoggedInListener!=null)
SetCheckIfLoggedInListener(null,new EventArgs());
}
and when calling you would need to do like:
//this will not work, because you invoke the event before subscribing
accountManager.CheckIfLoggedIn((o,e) => { Console.WriteLine("event fired"); });
Working DEMO Fiddle here
This way you can make it mandatory for user to register the implementation to be called when event is fired.
Hope it helps!

Related

C# What alternative ways are there to propagate an Event down a call chain?

Imagine that Main.cs calls sub.cs which calls action.cs. action.cs raises and event which sub.cs subscribes to, however, sub.cs does not care about the event it is only main.cs that wants to know about this so sub.cs raises the event again so that main.cs can subscribe to it and discover that action.cs has raised the original event; which seems so cumbersome.
What alternatives are there to passing events on through a chain of method calls?
You can directly attach event exposed in Sub at event exposed in Action, of course event need to be exposed both in Sub and in Action:
class SubClass
{
public event EventHandler MyEvent
{
add
{
_action.MyEvent += value;
}
remove
{
_action.MyEvent -= value;
}
}
private ActionClass _action;
}
With this solution you still have to declare event twice but you do not chain method calls and you can omit event handler in SubClass.
There are alternatives, of course, but you may need to change your design and I don't have enough context to suggest anything. In general I'd start with simplest possible solution. If you need just to bubble one event this may be enough but if you need to expose many of them then you may consider to introduce a third object which exposes what you need and make accessible through SubClass from ActionClass, something like this (but please with better names):
public sealed class Notifications
{
public event EventHandler MyEvent;
internal void RaiseMyEvent(EventArgs e)
{
var myEvent = MyEvent;
if (myEvent != null)
myEvent(this, e);
}
}
class MyAction
{
public Notifications Notifications
{
get { return _notifications; }
}
// ...
}
class SubClass
{
public Notifications Notifications
{
get { return _action.Notifications; }
}
// ...
}
Note that this example is just a proof of concept.
You may want to use pub-sub with topics, for instance see https://www.rabbitmq.com/tutorials/tutorial-three-dotnet.html
(You don't need rabbitmq for that you can implement simple pub-sub yourself or take one from github/MSDN see: https://msdn.microsoft.com/en-us/library/ms752254(v=vs.110).aspx, https://github.com/upta/pubsub/blob/master/README.md)
You could use a callback instead of events.
You can add a callback function as additional parameter to the methods of method chain.
E.g. if the method is doSomething() replace it with doSomething(Action action) and Main.c calls this method with Sub.doSomething(() => ReactToTheEvent()); and Action.cs calls action(); insetad of raising the event.

Provide feedback to event caller using writable property in EventArgs

In Dustin Campbell's answer in question Return a value from a Event — is there a Good Practice for this? it is stated that instead of returning data from an event handler, we can have a writable property on a set of custom EventArgs that is passed to the event similar to Cancel property of the WinForms FormClosing event.
How do I provide feedback to event caller using properties in EventArgs?
My specific scenario is that there is a Controller class that does Job A and there are many classes requesting the Job A to be done. Thus, the controller is subscribed to this event on all classes.
I want to give some feedback to the caller that the job is done. The tricky part is that those classes are module-like and controller doesn't know anything about them.
My though is to include that writable property to the delegate of the event in order for the controller to give feedback through it. This property could somehow be invoked using reflection, which is fine in my scenario.
you cannot define properties for delegates.
Also you do not need reflection for such a mechanism.
What you want to do is to define your "return"-properties in the EventArgs-derived class.
A simple such class would be:
public class JobEventArgs : EventArgs {
public bool Done { get; set; }
}
Now you can declare your event in the class as
public event EventHandler<JobEventArgs> Job;
Usage in the method which handles the event:
public void DoJob(object s, JobEventArgs args) {
// do stuff
args.Done = true;
}
and in the event invoking code:
public void FireJobEvent() {
var args = new JobEventArgs();
this.Job(this, args);
if(!args.Done) {
// the job was not handled
}
}
But frankly it rather seems like you want to do a job asynchronously with a notification when it finishes.
Which would result in syntax like..
class Module {
public void JobCompleted(IAsyncResult r) {
if(!r.IsCompleted)
return;
Console.WriteLine("The job has finished.");
}
public void ExecuteJob() {
var job = new EventArgs<JobEventArgs>((s, a) => { this.controller.JobA(); });
job.BeginInvoke(null, null,
r =>
{
this.JobCompleted(r);
if(r.IsCompleted)
job.EndInvoke(r);
}, null);
}
}

C# Create a Delegate that fires an event?

Is it possible to use Reflection is C# to fire an event? Say I have a situation like this:
public delegate void SomeEventHandler(object sender, BenArgs e);
class EventHub
{
public event SomeEventHandler SOME_EVENT;
public void fireEvent(String eventName)
{
SomeEventHandler evt = (SomeEventHandler) Delegate.CreateDelegate(typeof(SomeEventHandler), this, eventName);
evt.Invoke(null, null);
}
}
Meaning if I call
EventHub.fireEvent("SOME_EVENT")
then it makes the event hub fire SOME_EVENT? I've tried this and am just getting exceptions.
This is mostly a curiosity of mine, I know that in this case I could just as easily fire the event without reflection.
Assuming your current scenario, i.e.:
A field-like event.
The backing delegate-field has the same name as the event.
(this, EventArgs.Empty) are valid arguments to pass to the delegate.
You can do something like this (more argument validation required):
public void fireEvent(String eventName)
{
// Get a reference to the backing field
var del = (Delegate)typeof(EventHub)
.GetField(eventName, BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(this);
// Invoke the delegate, it's invocation-list will contain the listeners
if(del != null)
del.DynamicInvoke(this, EventArgs.Empty);
}
Usage:
var eHub = new EventHub();
eHub.SOME_EVENT += delegate { Console.WriteLine("SOME_EVENT fired.."); };
eHub.fireEvent("SOME_EVENT");
Now, you can generalize this idea with an extension method on object if you like, but all of this is a really bad idea. This problem can't be solved in the general case because one can't know how an event is "implemented." There could be arbitrary code inside the add and remove methods, and the logic to "fire" the event could also be just about anything. There might not even be a backing multicast delgate field to store the listeners.
In any case, trying to tell an object to fire an event is almost always a sign of a major design-flaw, IMO. If you still really do want this, it would be much better to declare a method like this in your class:
public void RaiseXXXEvent() { ... }

Prioritising Event Handlers

I have the following code where I am handling an event twice. However I always want to ensure that mynewclass always handles the event first and then the local event handler code fires. I understand the MyClass event should fire first as that is the one created first but because the thread and enqueuing is taking place, I think its taking too long and its doing something in myhandleeventlocal before I want it to do that. Any way I can wait for it to happen?
public MyMainClass
{
private MyMethod()
{
MyClass mynewclass = new MyClass();
mynewclass.myObject += MyHandler(myhandleventlocal);
mynewclass.loadedevent += EventHandler(loadedevent)
}
private void myhandleventlocal()
{
//do stuff
}
private void loadedevent()
{
//do some stuff
}
}
public MyClass
{
public MyObject myObject;
public event loadedevent;
public MyClass()
{
myObject = new MyObject();
myObject += MyHandler(myhandlevent);
}
private void myhandlevent(long value, string detail)
{
//Start a thread
//Enqueue value and detail
//On seperate thread dequeue value and process it
//Raise loadedevent event
}
}
UPDATE: I have updated my question and code to demonstrate the problem.
By default the event handlers are called in the order you add them, so if you always add the handlers in the order you want them to fire then it should work.
From Jon Skeet's article on events and delegates:
[...] extra delegates are both added to and removed from the end of the list [...]
Note: You can override the default behaviour of events by changing the add and remove operations on your event to specify some other behaviour. You can then keep your event handlers in a list that you manage yourself and handle the firing order based on whatever rules you like.
If you can't guarantee the order the event handlers will be added, just add the one for mynewclass and then in that code call the other code.
Since event handlers are called in the order you add them, based on the code I see in your question, you can't make mynewclass's handler be called first. The event handler that MyClass creates is always added first.
One solution would be to control priority for the event handlers. Instead of using the builtin event handler +=/-= operators, you would instead have methods for adding and removing events where you could specify ordering explicitly. That way, if a class knows it needs to handle the event first, it could ask for such. Be careful, though, because you could easily run into a situation where multiple classes are each insisting that they handle the event first.
Here is some quick and dirty code to get you started:
class MyClass {
private LinkedList<MyEventHandler> eventHandlers;
public enum Ordering { First, Last, ... };
public void AddHandler(MyEventHandler handler, Ordering order) {
switch(order) {
case Ordering.First:
eventHandlers.AddFirst(handler);
break;
// fill in other cases here...
}
}
public void RaiseEvent() {
// call handlers in order
foreach(MyEventHandler handler in eventHandlers)
eventHandler();
}
}
Referring to siride solution, you can also implement your handlers and decide the position that way. Like inverting the order (always add at the begin) or add some logic.

Need help understanding Events in C#

I'm a beginner in C# and having hard times understanding Events in C# .. The book i read (Illustrated C# 2008) gives an example about it , and there are few thing i need to ask about , so i will past the code here and point out the things i don't understand .
public class MyTimerClass
{
public event EventHandler Elapsed;
private void OnOneSecond(object source, EventArgs args)
{
if (Elapsed != null)
Elapsed(source, args);
}
}
class ClassA
{
public void TimerHandlerA(object obj, EventArgs e) // Event handler
{
Console.WriteLine("Class A handler called");
}
}
class ClassB
{
public static void TimerHandlerB(object obj, EventArgs e) // Static
{
Console.WriteLine("Class B handler called");
}
}
class Program
{
static void Main( )
{
ClassA ca = new ClassA(); // Create the class object.
MyTimerClass mc = new MyTimerClass(); // Create the timer object.
mc.Elapsed += ca.TimerHandlerA; // Add handler A -- instance.
mc.Elapsed += ClassB.TimerHandlerB; // Add handler B -- static.
Thread.Sleep(2250);
}
}
Ok, now the line after declaring the event here public event EventHandler Elapsed;
which is private void OnOneSecond(object source, EventArgs args) i know that the two line after it is to check if the event contains methods or not , but what is OnOneSecound for ? or when it's called ? or what it's named .. it's not event handler i guess right ? and what's the relationship between Elapsed and OnOneSecond ?
sorry for the newbie question .. and thanks in advance :)
the OnOneSecond method will be called internally by the MyTimerClass when it needs to invoke the event.
This is a common pattern used by most controls, including the microsoft ones.
Basically you dont need to be checking if the event is set in multiple places, you just do it in this one method then call this method internally to raise the event.
I tend not to pass the event args to the OnXXX method though, for example.
public event EventHandler<EventArgs> SomeEvent;
protected virtual void OnSomeEvent()
{
if (this.SomeEvent !=null)
{
this.SomeEvent.Invoke(this,EventArgs.Empty);
}
}
then to raise it
this.OnSomeEvent();
This is the method, that you call to raise the event safely.
the problem is, you can basically call
Elapsed(source, args)
but if there is noone connected to the event, this will raise a Reference Null exception. as the event is null, when nobody hears on it.
a better solution is, that you directly add a subscriber to the events. then you can safely call it directly. as there will be allways a subscriber.
public event Action<EventArgs> Elapsed = val => { };
(note that with the = its directly assigned. val => { } is a Lambda expression, that defines a empty subscriber.)
Also, look into the Reactive Framework for .net
if you want to do a lot of event stuff, this is the correct solution for it.
That allows you to manually fire the events from thein the class.
That is the standard pattern for raising internal events that's why it is private.
OnOneSecond is just a helper method defined to raise the event. You can use events without such methods, it is just an established pattern to wrap the if (Elapsed != null) check in a method with a name that starts with On...
Technically you could just use Elapsed(source, args) instead of OnOneSecond(source, args), but this will throw NullReferenceException if there are no listeners registered.

Categories

Resources