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.
Related
I have a player with the event "shoot". If the player shoots a bullet I manually trigger the event. A different GameObject has a script where if listener and if event triggered, listener perform specific method. I'm new to events. I really don't need delegate, only event. I'm teaching myself programming from internet but everywhere is how to use event only with delegate.
Can I have only event without delegate and if yes how to declare event like this?
An event is a delegate with safety constraint.
You can only call an event from the class that holds it.
You can only register/unregister to an event from outside the class (only +=/-=)
You cannot pass an event as parameter
You can only wipe clean an event from the class that holds it (eventName = null)
Off topic : UnityEvent is not a real event, it is a class that contain a list of delegate (Action).
When you call an event (or a delegate), you should always check for nullity as you never know if the reference points to an object. You do not need this with UnityEvent since as I mentioned it is not real event and then if the collection is empty nothing happens.
public delegate void MyDel();
// The two following behaves the same
public MyDel myDel;
public Action myAction;
public event Action myEvent;
void Start(){
if(myAction != null){ myAction(); }
if(myEvent != null) { myEvent(); }
if(myEvent != null) { myEvent.Invoke(); }
}
those are same things, but the choice of whether one or the other is based on what you want to do.
Consider the following in another class:
void Start(){
refToClass.myAction = MyMethod;
refToClass.myEvent += MyMethod;
}
void MyMethod(){}
First case will remove all methods attached to the delegate and MyMethod is then the only one left to listen.
The event will not allow that, only +=/-= are allowed so you can only remove/add a method without affecting the others.
A delegate basically describes a function type. An event is a hook where registered functions matching a given function type are called when the event occurs.
Putting together these two simplified definitions, a delegate is also a descriptor for an event, therefore you cannot have an event without a related delegate.
Anyway, you are not forced to declare a new delegate for every event you declare. Instead, you can use any of the preexisting delegates such as EventHandler, EventHandler<TEventArgs> or even any of the Action overloads, choosing in the one that fits you best in each case.
I believe you technically can have events without a delegate as described in the answers here.
However, delegates are used to pass information from where the event was raised. Without it, the program doesn't know where the event was called from and what information to pass.
This is a good introduction and there are lots of examples on SO to help with niche cases. For now, if you're self-learning programming, I'd recommend you learn the pattern and get it working before worrying about why the delegate and event always come as a pair.
public delegate void ShootEventHandler(object sender, ShootEventArgs e);
public class ShootEventArgs
{
public ShootEventArgs(string s) { Text = s; }
public String Text {get; private set;} // readonly
}
It's commmon to pass this in sender and then new up the delegate you created. Where you want to call shoot, you'd have something like this.
var handler = this.Shoot; // Get the event you want to fire
handler?.Invoke(this, new ShootEventArgs("Bang")); // tell eveything interested "Bang"
GameObjects interested in the shoot event can subscribe to the information like so:
this.Player.Shoot += this.ShootHandler;
public void ShootHandler(object sender, ShootEventArgs e) // common to use e for event args
{
Console.WriteLine(e.Text); // print "Bang"
}
Yes, you can declare an event without declaring a delegate by using Action. Action is in the System namespace. So make sure you add "using System;" statement at the top of your code file.
//No parameter
delegate void _delegate1();
static event _delegate1 _event1;
//Parameterized
delegate void _delegate2(bool flag);
static event _delegate2 _event2;
this is equivalent to
static event Action _event1;
static event Action<bool> _event2;
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.
If a class fires events in its methods, the class does not have to know what or who subscribes its events. It is not also important if there is any subscriber.
In the code below, if there is not any subscriber to OnTrigger event, an exception occures.
public class EventTrigger
{
public static void Main(string[] args)
{
(new EventTrigger()).Trigger();
}
public delegate void Delegate1();
public event Delegate1 OnTrigger;
void Trigger()
{
OnTrigger();
}
}
I can call the event like this;
if (OnTrigger != null)
{
OnTrigger();
}
But it seems weird to me, because the triggerer does not have to know about subscription.
My question is:
Do I have to check if the event reference is null whenever I use it.
If you initialize OnTrigger then you wont have to do the check.
e.g.
public event Action OnTrigger = delegate { };
Yes ´delegate { }´ instantiates a new object, which is why this allows you to omit the ´null´ check.
´delegate { }´ returns nothing, so if you want it to return a string (which you need if Delegate1 returns a string) then you simply add ´return "";´ e.g.:
public event Action OnTrigger = delegate { return string.Empty; };
One I should add is that it's bad practice to do this in order to avoid a null check, as it's a lazy mans hack. Some code can still set the event to null, ´OnTrigger = null´ will break your code. And when it comes to (de)serialization it wont work at all.
The triggerer doesn't have to know about the individual subscribers, but it does need to know about subscription. You have to either do the null check every time or use the work-around Simon suggested.
This is abit difficult to word, so I am going to rely mostly on code.
BTW if you can word the question in a better light please dont hesitate giving your 2c!
class CustomEventArgs : EventArgs
{
public delegate void CustomEventHandler( Object sender, CustomEventArgs args );
public int data;
public CustomEventArgs (int _data)
{
data = _data;
}
}
This is the event that we will be using in this example.
class EventGenerator
{
public event CustomEventArgs.CustomEventHandler WeOccasion;
public EventGenerator ()
{
Task.Factory.StartNew( () =>
{
var index = 1;
// just loop and generate events every now and then
while (true)
{
Thread.Sleep( 1000 );
WeOccasion( this, new CustomEventArgs (++index));
}
});
}
}
This class just loops through firing off CustomEventHandler events.
class EventActivity
{
// EventActivity has an event of the same type as EventGenerator's
public event CustomEventArgs.CustomEventHandler WeOccasion;
// this is the part I cant seem to get right
public event CustomEventArgs.CustomEventHandler Source ( get; set; }
public bool Active {
set
{
if (value)
{
Source += DoWork;
}
else
{
Source -= DoWork;
}
}
}
private void DoWork( Object sender, CustomEventArgs frame);
}
Here is where I really need help. I want almost a pointer to an event in an another class of type CustomEventHandler that I can later assign event handlers to when I activate the activity.
Here is a usage example wrapped in a class;
class EventAssigner
{
EventGenerator Generator;
EventActivity DoSomeThing1;
EventActivity DoSomeThing2;
public EventAssigner ()
{
// init
Generator = new EventGenerator();
DoSomeThing1 = new EventActivity();
DoSomeThing2 = new EventActivity();
// assign sources
DoSomeThing1.Source = Generator.WeOccasion;
DoSomeThing2.Source = DoSomeThing1.WeOccasion;
// activate the first activity
DoSomeThing1.Active = true;
}
public void Activate2()
{
// activate the second activity
DoSomeThing2.Active = true;
}
public void Deactivate2()
{
// deactivate the second activity
DoSomeThing2.Active = false;
}
}
Obiously this code doesnt work, and I suppose thats what I am asking. Can you get this design pattern to work?
What you're asking to do isn't really possible with .NET events, and probably isn't as desirable as you might think. A bit of background should help explain why:
Properties have a basic pattern with get and set operations. These are invoked by accessing the property (for a get) and an assignment to the property (for a set):
var x = instance.Prop1; // access
instance.Prop1 = x; // assignment
When you access an event from outside the class (i.e. instance.Event) you are given the "public" face, which, like properties, has two operations: add handler and remove handler. These are invoked using the += and -= operators.
instance.Event += this.Handler; // add
instance.Event -= this.Handler; // remove
The important thing to notice that it doesn't have a "get" operation - there is no way to get a reference to the event outside the class; you can only modify the handlers registered.
When you access an event from within a class, you are given the "private" face, which is essentially a special collection of delegates (function pointers) to the registered event handlers. When you invoke the delegate, you're actually asking the framework to iterate through the registered event handlers and invoke those.
if(this.Event != null)
{
this.Event.Invoke(e, args); // raise event
}
This separation of public face and private face is what allows you have a nice simple event keyword which magically gives you an event. It is also what stops you passing a reference to the event around.
To pass the event into registration methods, you have to pass the object the event is attached to. If you have multiple classes which implement the same event and you want to register them all in the same way, you should have them implement an interface with the event (yes, events can be on interfaces) and write your method to accept the interface as an argument.
If I'm reading you correct, you want the line
DoSomeThing1.Source = Generator.WeOccasion;
to save the pointer to the WeOccasion event, so that you can add the DoWork call to it later, right?
I don't think that is possible with "normal" code, as the event is not a value, but rather like a property. Consider the following analogous code:
myProp = aPerson.Name; // attempt to save the name property for later
myProp = "Fred"; // intent is to set aPerson.Name = "Fred"
If you want this to work I'd suggest using reflection to find the event, and add to it using the EventInfo.AddEventHandler method (http://msdn.microsoft.com/en-us/library/system.reflection.eventinfo.addeventhandler.aspx)
I'm currently developing a tiny technical Framework that is independant of any applications. Business code just refers to this Framework.
According this article : http://msdn.microsoft.com/en-us/library/5z57dxz2.aspx (exemple 2), we need to provide a delegate for the custom event.
Problem is, anyone can Invoke my handler (and then raise the event), even in my Business Code and that isn't logical for me, so what is the best way to raise a custom Event with a delegate that is only "internal" and not "public" ?
Thanks for help.
I am not sure if I get it right or not. I think that you feel like if you provide a public Delegate type for your custom event, anyone will be able to Raise that event.
Well, that is not true. Only the class that defines that custom event can raise it. If this is your issue, don't worry.
Not true. It's not allowed to invoke an event outside the class which the event belongs to. Others can only use += and -= operators to your event. Only in the class, you can invoke the event. That is a difference between an event and a normal delegate. That is:
public Data
{
public event EventHandler OnSave
public EventHandler OnLoad;
private void Load()
{
if (OnLoad!=null) OnLoad();
//other operations
}
private void Save()
{
if (OnSave!=null) OnSave();
//other operations
}
}
And outside the class:
Data data = new Data();
data.OnLoad += (s,e) => {};
data.OnSave += (s,e) => {};
data.OnLoad = (s,e)=>{};
//data.OnSave = (s,e)=>{}; //invalid
data.OnLoad();
//data.OnSave(); //invalid
The delegate is just a type declaration describing the "signature" of your event. This has to be public. To actually invoke your event you often implement a method named OnEvent (where you substitute Event with Click or Closed or whatever describes your event). This method should be private (or protected) in your class.
You cannot declare an event using a delegate that is less "visible" than the event.
Problem is, anyone can Invoke my handler (and then raise the event), even in my Business Code
That isn't true. You declare an event as follows:
public event FooEventHandler Foo;
The only thing that external code can do with the event is subscribe to it (+=), or unsubscribe from it (-=). It can't access the actual delegate, which is generated by the compiler as a private field. In other words, this code would be invalid :
SomeClass x = new SomeClass();
x.Foo(x, new FooEventArgs()); // compilation error here
Don't forget that an event is actually a pair of methods (add and remove). The compiler rewrites the event declaration to something along those lines:
private FooEventHandler _foo;
public event FooEventHandler Foo
{
add { _foo += value; }
remove { _foo -= value; }
}
(the generated code is actually a bit more complex, with some locking to ensure thread safety)
As you can see, the _foo field is private, so client code can't access it. Only the event's add and remove accessors are accessible.
One way of doing it:
Instead of public event, create a method that will manually subscribe your desired delegates, and store them in `private List _delegates' field.
Then, from the 'inside', call each of them when you desire.
public class Framework
{
public delegate void Method();
public void AttachEvent(Method M)
{
_methods.Add(M);
}
private List<Method> _methods;
private FireMethods()
{
_methods.Foreach(x=>x.Invoke());
}
}
Or, you can embrace 'by design' feature of the events that they aren't publicly Invoke()-able.
:)