Suppose I want to publish an event from the MarketDataProvider class. The problem is that the event logic resides 2 level deeper.MarketDataProvider --> Level1SocketClient --> Level1MessageHandler.
In short, I would like to raise the event from Level1MessageHandler that MarketDataProvider can publish. The performance here is critical because there are a lot of events generated. I would like to find a clean way of doing it without chaining events from each level.
Rather than having an Event itself, could the intermediate class just pass the Add and Remove calls on to the lowest level class? I.e.
public class Level1MessageHandler
{
public event EventHandler<MessageEventArgs> MessageReceived;
}
public class Level1SocketClient
{
Level1MessageHandler level1Handler;
public event EventHandler<MessageEventArgs> MessageReceived
{
add
{
level1Handler.MessageReceived += value;
}
remove
{
level1Handler.MessageReceived -= value;
}
}
}
This would at least cut out one level of delegate call.
(Or did I get the direction of invocation reversed? Anyway I think the idea is clear.)
Update
An interesting question arises: what happens if the intermediate listener needs to be disposable, and when disposed, remove all the events added through it? You can do it by recording the events added in a local event, like so:
public interface IMessagePublisher<TEventArgs> where TEventArgs : EventArgs
{
event EventHandler<TEventArgs> MessageReceived;
}
public class MessageRePublisher<TEventArgs> : IMessagePublisher<TEventArgs>, IDisposable where TEventArgs : EventArgs
{
readonly IMessagePublisher<TEventArgs> publisher;
public MessageRePublisher(IMessagePublisher<TEventArgs> publisher)
{
this.publisher = publisher;
}
EventHandler<TEventArgs> messageReceivedEventsAdded = null;
public event EventHandler<TEventArgs> MessageReceived
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
// events are multicast delegates, which are immutable. We need to remove the previous
// combined event, create a new combined event, then added that.
// More here: http://msdn.microsoft.com/en-us/magazine/cc163533.aspx
if (messageReceivedEventsAdded != null)
publisher.MessageReceived -= messageReceivedEventsAdded;
messageReceivedEventsAdded += value;
if (messageReceivedEventsAdded != null)
publisher.MessageReceived += messageReceivedEventsAdded;
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
if (messageReceivedEventsAdded != null)
publisher.MessageReceived -= messageReceivedEventsAdded;
messageReceivedEventsAdded -= value;
if (messageReceivedEventsAdded != null)
publisher.MessageReceived += messageReceivedEventsAdded;
}
}
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (messageReceivedEventsAdded != null && publisher != null)
{
publisher.MessageReceived -= messageReceivedEventsAdded;
}
}
messageReceivedEventsAdded = null;
}
#endregion
}
The intermediate listener combines all its events into a single concatenated event, then adds and removes that every time.
Related
I have a base class that contains the following events:
public event EventHandler Loading;
public event EventHandler Finished;
In a class that inherits from this base class I try to raise the event:
this.Loading(this, new EventHandler()); // All we care about is which object is loading.
I receive the following error:
The event 'BaseClass.Loading' can only appear on the left hand side of += or -= (BaseClass')
I am assuming I cannot access these events the same as other inherited members?
What you have to do , is this:
In your base class (where you have declared the events), create protected methods which can be used to raise the events:
public class MyClass
{
public event EventHandler Loading;
public event EventHandler Finished;
protected virtual void OnLoading(EventArgs e)
{
EventHandler handler = Loading;
if( handler != null )
{
handler(this, e);
}
}
protected virtual void OnFinished(EventArgs e)
{
EventHandler handler = Finished;
if( handler != null )
{
handler(this, e);
}
}
}
(Note that you should probably change those methods, in order to check whether you have to Invoke the eventhandler or not).
Then, in classes that inherit from this base class, you can just call the OnFinished or OnLoading methods to raise the events:
public AnotherClass : MyClass
{
public void DoSomeStuff()
{
...
OnLoading(EventArgs.Empty);
...
OnFinished(EventArgs.Empty);
}
}
You can only access an event in the declaring class, as .NET creates private instance variables behind the scenes that actually hold the delegate. Doing this..
public event EventHandler MyPropertyChanged;
is actually doing this;
private EventHandler myPropertyChangedDelegate;
public event EventHandler MyPropertyChanged
{
add { myPropertyChangedDelegate += value; }
remove { myPropertyChangedDelegate -= value; }
}
and doing this...
MyPropertyChanged(this, EventArgs.Empty);
is actually this...
myPropertyChangedDelegate(this, EventArgs.Empty);
So you can (obviously) only access the private delegate instance variable from within the declaring class.
The convention is to provide something like this in the declaring class..
protected virtual void OnMyPropertyChanged(EventArgs e)
{
EventHandler invoker = MyPropertyChanged;
if(invoker != null) invoker(this, e);
}
You can then call OnMyPropertyChanged(EventArgs.Empty) from anywhere in that class or below the inheritance heirarchy to invoke the event.
I am assuming I cannot access these events the same as other inherited members?
Precisely. It's customary to provide a protected function OnXyz or RaiseXyz for each event in the base class to enable raising from inherited classes. For example:
public event EventHandler Loading;
protected virtual void OnLoading() {
EventHandler handler = Loading;
if (handler != null)
handler(this, EventArgs.Empty);
}
Called in the inherited class:
OnLoading();
You can try this way, It works for me:
public delegate void MyEventHaldler(object sender, EventArgs e);
public class B
{
public virtual event MyEventHaldler MyEvent;
protected override void OnChanged(EventArgs e)
{
if (MyEvent != null)
MyEvent(this, e);
}
}
public class D : B
{
public override event MyEventHaldler MyEvent;
protected override void OnChanged(EventArgs e)
{
if (MyEvent != null)
MyEvent(this, e);
}
}
not to resurrect an old thread but in case anybody is looking, what I did was
protected EventHandler myPropertyChangedDelegate;
public event EventHandler MyPropertyChanged
{
add { myPropertyChangedDelegate += value; }
remove { myPropertyChangedDelegate -= value; }
}
This lets you inherit the event in a derived class so you can invoke it without requiring to wrap the method while keeping the += syntax. I guess you could still do that with the wrapping methods if you did
public event EventHandler MyPropertyChanged
{
add { AddDelegate(value); }
remove { RemoveDelegate(value); }
}
I got this event handle and how can I do unit test for this
public class MyLearningEvent
{
private event EventHandler _Closed;
public event EventHandler Closed
{
add
{
_Closed -= value;
_Closed += value;
}
remove
{
_Closed -= value;
}
}
public void OnClosed()
{
if (_Closed != null) _Closed(this, EventArgs.Empty);
}
}
Just modified code so that much clear
Thanks
You should not unit test that code. It's a feature which is built into .NET. Your event handling is flawed imho.
add
{
_Closed -= value;
_Closed += value;
}
Probably means that your invokers don't keep track on if they have subscribed or not. That can lead to memory leaks: http://blog.naviso.fr/wordpress/wp-content/uploads/2011/11/MemoryLeaks-English.jpg
A more robust (and thread safe implementation) is:
public class MyLearningEvent
{
public event EventHandler Closed = delegate {};
public void TriggerClosed()
{
Closed(this, EventArgs.Empty);
}
}
But you should not let anyone else trigger that event (make the TriggerClosed private/protected)
Try this method. This assumes MyClass.Close() raises the MyClass.Closed event.
public void ClosedEventHandlerIsNotCalledAfterBeingRemoved()
{
MyLearningEvent Target = new MyLearningEvent();
EventHandler Target_Closed = new EventHandler((sender, e) => { Assert.Fail("Closed EventHandler was raised after being removed."); });
Target.Closed += Target_Closed;
Target.Closed -= Target_Closed;
Target.OnClosed();
}
I have three objects ObjectA has an ObjectB, ObjectB has an ObjectC. When ObjectC fires an event I need ObjectA to know about it, so this is what I've done...
public delegate void EventFiredEventHandler();
public class ObjectA
{
ObjectB objB;
public ObjectA()
{
objB = new ObjectB();
objB.EventFired += new EventFiredEventHandler(objB_EventFired);
}
private void objB_EventFired()
{
//Handle the event.
}
}
public class ObjectB
{
ObjectC objC;
public ObjectB()
{
objC = new ObjectC();
objC.EventFired += new EventFiredEventHandler(objC_EventFired);
objC.FireEvent();
}
public event EventFiredEventHandler EventFired;
protected void OnEventFired()
{
if(EventFired != null)
{
EventFired();
}
}
private void objC_EventFired()
{
//objC fired an event, bubble it up.
OnEventFired();
}
}
public class ObjectC
{
public ObjectC(){}
public void FireEvent()
{
OnEventFired();
}
public event EventFiredEventHandler EventFired;
protected void OnEventFired()
{
if(EventFired != null)
{
EventFired();
}
}
}
Is this the proper way to handle this, or is there a better way? I don't want ObjectA to know about ObjectC at all, only that it raised an event.
Another approach, is to wrap it using add/remove:
public class ObjectB
{
ObjectC objC;
public ObjectB()
{
objC = new ObjectC();
}
public event EventFiredEventHandler EventFired
{
add { this.objC.EventFired += value; }
remove { this.objC.EventFired -= value; }
}
}
That's the way I do it. however I would recommend change your firing mechanism to this to make it thread safe
protected void OnEventFired()
{
var tmpEvent = EventFired;
if(tmpEvent != null)
{
tmpEvent();
}
}
This keeps it from failing if EventFired becomes null between the null check and the firing.
Also it is somewhat of a standard to follow the EventHandler pattern for your event delegates.
protected virtual void OnEventFired(EventArgs e)
{
var tmpEvent = EventFired;
if(tmpEvent != null)
{
tmpEvent(this, EventArgs.e);
}
}
I was wrong about the threadsafe pattern, here is the full threadsafe event pattern
/// <summary>
/// Delegate backing the SomeEvent event.
/// </summary>
SomeEventHandler someEvent;
/// <summary>
/// Lock for SomeEvent delegate access.
/// </summary>
readonly object someEventLock = new object();
/// <summary>
/// Description for the event
/// </summary>
public event SomeEventHandler SomeEvent
{
add
{
lock (someEventLock)
{
someEvent += value;
}
}
remove
{
lock (someEventLock)
{
someEvent -= value;
}
}
}
/// <summary>
/// Raises the SomeEvent event
/// </summary>
protected virtual OnSomeEvent(EventArgs e)
{
SomeEventHandler handler;
lock (someEventLock)
{
handler = someEvent;
}
if (handler != null)
{
handler (this, e);
}
}
As other answers have stated, this is they way to do it.
But you can go beyond!!! I've just implemented a good data structure on it, and it's like to give you a spin on it.
Would be nice to have an automatic event bubbling? You could implement it using Reflection. My way is to define an Interface/Base class which declares an event (or a set of events). Then, the parameterless constructor of a base class will iterate other its properties/fields, and register automatically the members events for event propagation.
There are some restriction on design, but if you have a deep structure and/or many (structured) events, it could be nice to have everything setup without any additional line of code.
An initial base class could be:
class BaseObject {
public BaseObject() {
FieldInfo[] fInfos = this.GetType().GetFields(...);
foreach (FieldInfo fInfo in fInfos) {
object fInfoValue = fInfo.GetValue(this, null);
if (fInfoValue is BaseObject) {
BaseObject bMemberObject = (BaseObject)fInfoValue;
bMemberObject.MyEvent += new EventHandler(delegate() {
if (this.MyEvent != null)
MyEvent();
});
}
}
public event MyEvent = null;
}
Of course, as already suggested, follow the event delegate delegate(object sender, EventArgs args) (I've used a simpler event for clarity).
Naturally, is implicit that you classes A, B and C derives directly from BaseObject.
Note that any logic could be implemented to bind structured events (you could be the nested event registration using the name and/or other reflected properties.
I am making a windows forms project in C#, in which I made a class LabelX which inherits System.Windows.Forms.Label, then added a property Mass of float type
Now, my question is how can I handle, when value of Mass is changed.
e.g.:
When user enter value zero or less than zero
I want to fire a message that "Mass can't be zero or negative"
If I am interpreting this correctly, there are two parts to this. First, you need to detect invalid values and throw exceptions. Second, you need to raise an event when the property changes. This can be achieved as follows.
private float mass;
public float Mass
{
get
{
return this.mass;
}
set
{
if (value <= 0.0F)
{
throw new ArgumentOutOfRangeException("Mass cannot be zero or negative.");
}
if (this.mass != value)
{
this.mass = value;
OnMassChanged(EventArgs.Empty);
}
}
}
public event EventHandler MassChanged;
protected virtual void OnMassChanged(EventArgs args)
{
var handler = this.MassChanged;
if (handler != null)
{
handler(this, args);
}
}
To show a message if an invalid entry is made, you should put a try \ catch block around the call to set Mass and catch the ArgumentOutOfRangeException.
Try the following:
// Created an empty form with a LabelX control on it.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Added this event from the property manager.
private void labelX1_MassChanged(object sender, EventArgs e)
{
var label = (LabelX)sender;
if (label.Mass <= 0.0)
MessageBox.Show("Mass is less than or equal to 0");
}
}
public class LabelX : Label
{
private float _mass;
public float Mass
{
get { return _mass; }
set
{
if (!value.Equals(_mass))
{
_mass = value;
OnMassChanged(EventArgs.Empty);
}
}
}
public event EventHandler MassChanged;
protected virtual void OnMassChanged(EventArgs e)
{
if (MassChanged != null)
MassChanged(this, e);
}
}
Outside of your LabelX class, create the following class:
public class MassChangedEventArgs : EventArgs
{
public float Mass { get; private set; }
public MassChangedEventArgs(float mass)
{
this.Mass = mass;
}
}
Also outside of your LabelX class, create the following delegate. This will be your event handler.
public delegate void MassChangedEventHandler(object sender, MassChangedEventArgs e);
Within your LabelX class, create an event to broadcast:
public class LabelX
{
public event MassChangedEventHandler MassChanged;
//the rest of your code here...
}
You'll also want to create a private instance method that will fire your event.
public class LabelX
{
public event MassChangedEventHandler MassChanged;
private void OnMassChanged()
{
if(MassChanged!=null)
this.MassChanged(this, new MassChangedEventArgs(this.Mass));
}
//the rest of your code here...
}
Finally, whenever your Mass property changes, call OnMassChanged. For instance:
public class LabelX
{
private float mass;
public float Mass
{
get
{
return mass;
}
set
{
mass = value;
OnMassChanged();
}
}
public event MassChangedEventHandler MassChanged;
private void OnMassChanged()
{
if(MassChanged!=null)
this.MassChanged(this, new MassChangedEventArgs(this.Mass));
}
//the rest of your code here...
}
When you want to handle that event on a per-instance basis, you just have to register a listener with the MassChanged event of your underlying object and perform whatever actions are necessary.
Events are a common pattern used in the framework. The process typically involves defining a delegate to be used as the event handlers, declaring the event using the handler, defining methods to raise the event, then hooking up to the properties the logic to raise the event.
The message you describe is better done as an Exception but here's an example to define the MassChanged event.
// Define event args if you have additional
// information to pass to your event handlers
public class MassChangedEventArgs : EventArgs
{
public MassChangedEventArgs(int oldMass)
{
OldMass = oldMass;
}
public int OldMass { get; private set; }
}
public class SomeObject
{
// There's a generic event handler delegate that can be
// used so you only need to define the event arguments.
public event EventHandler<MassChangedEventArgs> MassChanged;
// Convenience method to raise the event
protected virtual void OnMassChanged(MassChangedEventArgs e)
{
if (MassChanged != null)
MassChanged(this, e);
}
public int Mass
{
get
{
return mass;
}
set
{
// Your checks here
if (value <= 0)
throw new ArgumentOutOfRangeException("Mass", "Mass can't be zero or negative");
// Should only raise the event if the new value is different
if (value != mass)
{
// Change the mass
MassChangedEventArgs e = new MassChangedEventArgs(mass);
mass = value;
// Raise the event
OnMassChanged(e);
}
}
}
private int mass;
}
After that, it's just a matter of registering handlers to the event and going from there.
I am quite sure you you would like to 'fire' an exception in your case.
This more of a validation logic issue such AOP code contracts concept.
But if you really like to create an event for it you have to at least:
1) create an event storage variable in your label class
public event EventHandler MassChanged;
2) in your property (note that you loose the ability to use code gen functions of c# 3 for
which 'auto' implement the field to store your Mass property value)
public bool Mass
{
get { return _mass; }
set {
// check if value is invalid (0 or less) && that event subscribers exist
if(value<=0 && MassChanged != null) { MassChanged(this, null); }
else // otherwise assign ...
{
_mass = value;
}
}
}
3) create an event handler of type EventHandler
Best to read the msdn article for events: link text
Again I am pretty sure you are not handling exceptions properly in the app
if you need an event for this. I mean there is nothing wrong but events are
usually not used as means of value validations.
I have a class which wraps another class and exposes several events from the class it's wrapping. (The instance it wraps can change)
I used the following code:
public event EventHandler AnEvent;
public OtherClass Inner {
get { /* ... */ }
set {
//...
if(value != null)
value.AnEvent += AnEvent;
//...
}
}
However, the events were raised inconsistently.
What's wrong with this code?
The problem is that Delegates are immutable.
If you add a handler to an event, it creates a new Delegate instance which contains the old handlers and the newly added handler. The old Delegate is not modified and is discarded.
When I write, value.AnEvent += AnEvent, it adds the Delegate containing the current handlers (if any) to the inner class's event. However, changes to the outer class's event are ignored because they don't change the Delegate instance that I added to the inner classes event. Similarly, if I remove a handler after setting the Inner property, the handler isn't removed from the inner class's event.
There are two correct ways to do this.
I can make my own handler that invokes the wrapper's event, like this:
public event EventHandler AnEvent;
public OtherClass Inner {
get { /* ... */ }
set {
if(Inner != null)
Inner.AnEvent -= Inner_AnEvent;
//...
if(value != null)
value.AnEvent += Inner_AnEvent;
//...
}
}
void Inner_AnEvent(object sender, EventArgs e) {
var handler = AnEvent;
if (handler != null) handler(sender, e);
}
The other way is to make a custom event in the wrapper that adds its handlers to the inner class's event, like this:
EventHandler anEventDelegates
public OtherClass Inner {
get { /* ... */ }
set {
//...
if(value != null)
value.AnEvent += anEventDelegates;
//...
}
}
public event EventHandler AnEvent {
add {
anEventDelegates += value;
if (Inner != null) Inner.AnEvent += value;
}
remove {
anEventDelegates -= value;
if(Inner != null) Inner -= value;
}
}
Note that this is not entirely thread-safe.
I solved this problem myself and am posting the question & answer for the benefit of people with similar problems.
The your answer - there are two problems here...
First: in both cases, you are raising the outer event with the wrong sender. Someone subscribing to an event on the outer class would expect those classes to be raised with a sender of that outer class.
This is particularly important in things like winform Controls, or binding-list implementations, where the sender is used to identify the object between many that share a handler.
This should instead be something like:
void Inner_AnEvent(object sender, EventArgs e) {
var handler = AnEvent;
if (handler != null) handler(this, e);
}
The second (much more minor) issue is that you are currently taking out an event on the inner class even if the outer class has no subscribers. You can fix this with a bit more custom handling...
private EventHandler anEvent;
public event EventHandler AnEvent {
add { // note: not synchronized
bool first = anEvent == null;
anEvent += value;
if(first && anEvent != null && inner != null) {
inner.SomeEvent += Inner_AnEvent;
}
}
remove { // note: not synchronized
bool hadValue = anEvent != null;
anEvent -= value;
if(hadValue && anEvent == null && inner != null) {
inner.SomeEvent -= Inner_AnEvent;
}
}
}
(and similar code in the Inner get/set to only subscribe if we have listeners...
if(value != null && anEvent != null)
value.AnEvent += Inner_AnEvent;
This might be a big saver if you have lots of instances of the outer-class, but rarely use the event.