What are the effects of adding EventHandler += EventHandler?
I have a SelectionChanged
event in class A that I want to relay through class B. I assumed that declaring a SelectionChanged
event in class B and assigning this EventHandler to A.SelectionChanged
would cause B.SelectionChanged
to trigger whenever A.SelectionChanged
was triggered - this turned out to be false.
To be more clear, some code:
class A
{
public event EventHandler SelectionChanged;
public void TriggerSelectionChanged()
{
if (SelectionChanged != null) SelectionChanged(this, EventArgs.Empty);
}
}
class B
{
private A _a = new A();
public A A { get { return _a; } }
public event EventHandler SelectionChanged;
public B()
{
A.SelectionChanged += SelectionChanged;
}
public static void Test()
{
B relayer = new B();
bool wasRelayed = false;
relayer.SelectionChanged += delegate { wasRelayed = true; };
relayer.A.TriggerSelectionChanged();
System.Console.WriteLine("Relayed: {0}", wasRelayed);
}
}
开发者_StackOverflow中文版
This prints out "Relayed: false".
What are the effects of adding an EventHandler to another EventHandler?
EDIT: Note! I'm aware of that a solution to this is to relay the event through an delegate, function etc etc, but I'm mostly interrested in knowning what the effects of this code is.
There is nothing in your code that 'connects' the invocation of B.SelectionChanged
to A.SelectionChanged
. Therefore, when you fire a SelectionChanged
on A
, your delegate that handles SelectionChanged
on B
is not invoked.
I think what you want is for your event on B to acts as an adapter on the event that A exposes? If this is the case, you will need to write your own add
/ remove
logic. See the following:
Events + Adapter Pattern
Another example of add / remove:
C#: event with explicity add/remove != typical event?
In this case B's SelectionChanged and A's SelectionChanged are not related.
If you were to make B inherit from A and remove the second declaration on B then this would work.
class A
{
public EventHandler SelectionChanged;
public void TriggerSelectionChanged()
{
if (SelectionChanged != null) SelectionChanged(this, EventArgs.Empty);
}
}
class B : A
{
public static void Test()
{
B relayer = new B();
bool wasRelayed = false;
relayer.SelectionChanged += delegate { wasRelayed = true; };
relayer.TriggerSelectionChanged();
System.Console.WriteLine("Relayed: {0}", wasRelayed);
}
}
Or you can pump your messages through...
class A
{
public EventHandler SelectionChanged;
public void TriggerSelectionChanged()
{
if (SelectionChanged != null) SelectionChanged(this, EventArgs.Empty);
}
}
class B
{
public B()
{
this._a.SelectionChanged += (o, s) =>
{
if(this.SelectionChanged != null) { this.SelectionChange(o, s); }
};
}
private A _a = new A();
public A A { get { return _a; } }
public EventHandler SelectionChanged;
public static void Test()
{
B relayer = new B();
bool wasRelayed = false;
relayer.SelectionChanged += delegate { wasRelayed = true; };
relayer.A.TriggerSelectionChanged();
System.Console.WriteLine("Relayed: {0}", wasRelayed);
}
}
It turns out that this is an effect from EventHandler being a Delegate. This class implements operator += through (or so I assume) using Delegate.Combine. The documentation of this function reads
Concatenates the invocation lists of the specified multicast (combinable) delegates.
What happens is that all handlers assigned to the EventHandler on the right side are added to the EventHandler on the left. In this case there's zero handlers so nothing happens. However, if the order of things are changed such that B.SelectionChanged
is assigned before B.SelectionChanged
is connected to A.SelectionChanged
things are hooked up correctly. However, removing an handler from B does not remove it from A so doing this should be highly frawned upon.
精彩评论