Check if event has any listeners? - c#

Is it possible to detect if event has any listeners? (I need to dispose my event provider object, if nobody needs it)

Assume the class is in a 3rd party library and it can't be modified:
public class Data
{
public event EventHandler OnSave;
//other members
}
In your program:
Data d = new Data();
d.OnSave += delegate { Console.WriteLine("event"); };
var handler = typeof(Data).GetField("OnSave", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(d) as Delegate;
if (handler == null)
{
//no subscribers
}
else
{
var subscribers = handler.GetInvocationList();
//now you have the subscribers
}

You can check if event is != null.
By the way, in C# you need this check each time you raise an event:
if (TheEvent != null) {
TheEvent(this, e);
}
and the reason is exactly to check if the event has any listener.
EDIT
Since you can't access TheEvent from outside the class, you could implement a method that does the check:
public class TheClass {
public bool HasEventListeners() {
return TheEvent != null;
}
}

void Main()
{
Console.WriteLine(ContainsOnSomethingEvent()); // false
OnSomething += (o,e) => {};
Console.WriteLine(ContainsOnSomethingEvent()); // true
}
EventHandler mOnSomething;
event EventHandler OnSomething {
add { mOnSomething = (EventHandler)EventHandler.Combine(mOnSomething, value); }
remove { mOnSomething = (EventHandler)EventHandler.Remove(mOnSomething, value); }
}
public bool ContainsOnSomethingEvent() {
return mOnSomething != null && mOnSomething.GetInvocationList().Length > 0;
}

Related

Connect Multiple event to same method in c#

I have three event like this:
public static event EventHandler BelowLowLimit;
public static event EventHandler AboveHighLimit;
public static event EventHandler PercentBelowLowLimit;
protected virtual void OnThresholdReached()
{
EventHandler handler = null;
if (rs.Value < rs.LowLimit)
{
handler = BelowLowLimit;
}
else if (rs.Value > rs.UpperLimit)
{
handler = AboveHighLimit;
}
if (handler != null)
{
handler(this, new EventArgs());
}
}
I have to raise event based on following condition:
public long Rs
{
get { return rs.Value; }
set
{
if (rs.Value < rs.LowLimit)
{
OnThresholdReached();
}
else if (rs.Value > rs.UpperLimit)
{
OnThresholdReached();
}
else
{
this.rs.Value = value;
}
}
}
What I want to connect this event to same method to raise the event. Is this correct way to do it?
please suggest me how to do it?
Are you looking at something like this?
protected virtual bool CheckForThresholds(long rsValue, long rsLowLimit, long rsUpperLimit)
{
EventHandler handler = null;
if (rsValue < rsLowLimit)
{
handler = BelowLowLimit;
}
else if (rsValue > rsUpperLimit)
{
handler = AboveHighLimit;
}
if (handler != null)
{
handler(this, new EventArgs());
return true;
}
return false;
}
public long Rs
{
get { return rs.Value; }
set
{
if (!CheckForThresholds(value, rs.LowLimit, rs.UpperLimit))
{
this.rs.Value = value;
}
}
}

c# check if event is null

I have this event in a webservice:
public event FindProductsByCharacteristicsCompletedEventHandler FindProductsByCharacteristicsCompleted
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
_findProductsByCharacteristicsCompleted += value;
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
_findProductsByCharacteristicsCompleted -= value;
}
}
And im then checking if the event value is null with this later in the class:
private void OnFindProductsByCharacteristicsOperationCompleted(object arg)
{
var handler = _findProductsByCharacteristicsCompleted;
if (handler == null)
return;
handler(this, new FindProductsByCharacteristicsCompletedEventArgs(completedEventArgs.Results, completedEventArgs.Error, completedEventArgs.Cancelled, completedEventArgs.UserState));
}
Your event implementation looks like it is an endless recursion. You are using the property itself in its implementation.
Change it to this:
private FindProductsByCharacteristicsCompletedEventHandler
_findProductsByCharacteristicsCompleted;
public event FindProductsByCharacteristicsCompletedEventHandler
FindProductsByCharacteristicsCompleted
{
[MethodImpl(MethodImplOptions.Synchronized)]
add
{
_findProductsByCharacteristicsCompleted += value;
}
[MethodImpl(MethodImplOptions.Synchronized)]
remove
{
_findProductsByCharacteristicsCompleted -= value;
}
}
And now, implement your method like this:
var handler = _findProductsByCharacteristicsCompleted;
if(handler == null)
return;
handler(this, new FindProductsByCharacteristicsCompletedEventArgs(...));
This has the advantage that it is thread-safe.
Even if someone detached the last handler from the event after you checked for null but before you actually raised the event, you would not get an exception, because you are operating on the unchanged local variable.

How to write a Trigger?

I want my C# code to call an event whenever a value is assigned to my object.
How exactly would I need to go about that?
class MyClass {
ManualResetEvent mre;
public MyClass() {
mre = new ManualResetEvent(false);
Data = null;
}
public object Data { get; set; }
void DataSet(object sender, EventArgs e) {
Console.WriteLine("object Data has been set.");
mre.Set();
}
}
Delegates don't seem to be what I need. An event, maybe? How would I write such an event, if so?
MyClass mc;
void processA() {
mc = new MyClass();
mc.Data = GetDataFromLongProcess();
}
private object data;
public object Data {
get { return data;}
set {
if(value != data) {
data = value;
OnDataChanged();
}
}
}
protected virtual void OnDataChanged() {
EventHandler handler = DataChanged;
if(handler != null) handler(this, EventArgs.Empty);
}
public event EventHandler DataChanged;
then hook any code to the DataChanged event. For example:
MyClass mc = ...
mc.DataChanged += delegate {
Console.WriteLine("new data! wow!");
};
If you want to fire an event when your property is set, you would do something like this:
public event Action OnDataChanged;
protected object _data = null;
public object Data
{
get { return _data; }
set
{
_data = value;
if(OnDataChanged != null)
OnDataChanged();
}
}
Then you would simply wire up event handlers to your object like so:
mc = new MyClass();
mc.OnDataChanged += delegate() { Console.WriteLine("It changed!"); };
mc.Data = SomeValue();
I think you're on the right track with an event-based model. Also take a look at the Observer pattern (which is the basis for .Net delegates and events underneath it all, as I understand):
http://www.dofactory.com/Patterns/PatternObserver.aspx
But the bottom line, as the other useful answer so far (Mr. Gravell's implementation) indicates, you're going to have to have code IN the setter to get it hooked up. The only alternative would be to poll the value for changes, which just smells bad to me.
you could implement INotifyPropertyChanged (this is more or less a event) or you could take your class a Action (Trigger) and call this, whenn the property changed.
Just don't use automatic properties but a concrete setter and call your event/trigger from there.
Conceptually, you would define an event in your class, and in your property set blocks, you would invoke the event with the necessary arguments to determine what just happened.
public event SomeDelegateThatTakesIntAsParameter myEvent;
void SetData(int data)
{
if(myEvent!= null)
myEvent(data)
}

Question about custom events

I'm making custom events for C# and sometimes it isn't working.
This is how I'm making the event happen:
private bool isDoorOpen;
public bool IsDoorOpen {
get { return isDoorOpen;}
private set { isDoorOpen = value; DoorsChangeState(this, null);}
}
And these are the event declarations:
//events
public delegate void ChangedEventHandler(Elevator sender, EventArgs e);
public event ChangedEventHandler PositionChanged;
public event ChangedEventHandler DirectionChanged;
public event ChangedEventHandler BreaksChangeState;
public event ChangedEventHandler DoorsChangeState;
This works as long as there are methods attached to the events, but if there isn't, it throws a null ref exception. What am I doing wrong?
The recommended way to call an event is
var handler = this.DoorsChangeState;
if (handler != null)
handler(this, null);
The reason for copying the handler locally is incase the event handler changes on another thread while you're checking for null.
EDIT: Found the article talking about race conditions.
http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx
I know this question has been discussed (and answered) several times here on SO.
Also somewhere here i got the following extension methods to make this pattern more easy to use:
public static class EventHandlerExtensions
{
public static void FireEvent<T>(this EventHandler<T> handler, object sender, T args) where T : EventArgs
{
var temp = handler;
if (temp != null)
{
temp(sender, args);
}
}
public static void FireEvent(this EventHandler handler, object sender)
{
var temp = handler;
if (temp != null)
{
temp(sender, EventArgs.Empty);
}
}
}
So in your code you can say:
public bool IsDoorOpen
{
get { return isDoorOpen;}
private set
{
isDoorOpen = value;
DoorsChangeState.FireEvent(this);
}
}
If a event isn't subscribed to when it fires, a NullReferenceException will be thrown. This is correct behaviour, not something you've done wrong.
You should check:
if(DoorsChangeState != null)
{
DoorsChangeState(this, null); // Only fire if subscribed to
}
Before invoking an event you must check if the event is null:
if (DoorsChangeState != null)
DoorsChangeState(this, null);
When DoorsChangeState is null that means there are no listeners on that event.
You need to check to see if the event has been subscribed to.
I use this standard form for throwing all of my events.
var temp = EventName;
if(EventName!= null)
temp(this, null);

Adding one event handler to another

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.

Categories

Resources