Reputation: 1171
I want to create a fluent extension method for subscribing to (and less importantly unsubscribing from) an event. That is an extension with the usage .RespondBy(Method)
in place of a += new Eventhandler(Method)
I want to do this: object.WhenSomethingChanges.RespondBy(DoingThisOtherThing);
Instead of this: object.WhenSomethingChanges += new EventHandler(DoingThisOtherThing);
I did a bunch of googling and while I didn't exactly grasp the intricate details, I do understand now that this has to do with whether you are accessing the local field or the public event.
With that said, I am simply interested in "how" this can be done and not concerned with "why" my first attempt hasn't worked. Failing a workaround, at least a definitive "You can not do this... at all, ever." would also be useful information...
CommuncationsStatusPresenter (Image)
CommuncationsStatusPresenter (Code)
using System;
using InspectionStation.Models;
using InspectionStation.Views;
using MachineControl.OPC;
namespace InspectionStation.Presenters
{
public class CommuncationsStatusPresenter
{
// Fields
private ICommunicationsModel m_model;
private ICommunicationsView m_view;
// Constructor
public CommuncationsStatusPresenter
(ICommunicationsModel p_model, ICommunicationsView p_view)
{
m_model = p_model;
m_view = p_view;
HookEvents();
}
private void HookEvents()
{
m_model
.When_Communications_Pulses_Heartbeat
.RespondBy(Setting_the_state_of_an_Indicator);
}
// Eventhandler
void Setting_the_state_of_an_Indicator(Tag sender, EventArgs e)
{
bool State = sender.BooleanValue;
m_view.Set_Communications_Status_Indicator = State;
}
}
}
RespondBy
using System;
namespace Common.Extensions
{
public static partial class ExtensionMethods
{
public static
void RespondBy<TSender, TEventArgs>(this
GenericEventHandler<TSender, TEventArgs> p_event,
GenericEventHandler<TSender, TEventArgs> p_handler
) where TEventArgs : EventArgs
{
p_event += new GenericEventHandler<TSender, TEventArgs>(p_handler);
}
}
}
using System;
namespace Common
{
[SerializableAttribute]
public delegate void GenericEventHandler<TSender, TEventArgs>
(TSender sender, TEventArgs e)
where TEventArgs : EventArgs;
}
ICommunicationsModel
using System;
using Common;
using MachineControl.OPC;
namespace InspectionStation.Models
{
public interface ICommunicationsModel
{
event GenericEventHandler<Tag, EventArgs>
When_Communications_Pulses_Heartbeat;
}
}
ICommunicationsView
namespace InspectionStation.Views
{
public interface ICommunicationsView
{
bool Set_Communications_Status_Indicator { set; }
}
}
Upvotes: 2
Views: 1379
Reputation: 1171
Given Michael Perrenoud's answer, I have settled on doing the following as part of my pattern...
public class CommuncationsStatusPresenter
{
...
private void HookEvents()
{
m_model.
When_Communications_Pulses_Heartbeat += new EventHandler<Tag, EventArgs>(
Set_the_state_of_an_Indicator);
}
// Eventhandler
void Set_the_state_of_an_Indicator(Tag sender, EventArgs e)
{
...
}
}
}
It's nothing special... just conistent auto-formatting based on new lines, but seems to be the best solution at this time (ie. I can almost read the code aloud to quickly decern its intent without resorting to extensive commented descriptions).
Note: I renamed the long GenericEventHandler
to simply EventHandler
as there's not much need for a special name.
Upvotes: 1
Reputation: 67898
Because the C# compiler strictly requires that events used outside the class must be followed by a +=
or -=
, the attach and detach commands for handlers, it won't be possible to extend and use this outside of the class.
However, if you're willing to build more specific methods on the class itself like:
object.RespondWhenSomethingChangesBy(DoingThisOtherThing);
then you could, inside of that method, leverage the extension method because that class defined the event. I know it means you'd be building a lot of boiler plate code for the events, but if this is what you really want then the aforementioned might be found to be even more streamlined than:
object.WhenSomethingChanges.RespondBy(DoingThisOtherThing);
I do fully understand your position here, and hope that Microsoft chooses to allow events to be extended in the future (I can think of some interesting reasons I'd use it), but until then I guess we'll just have to work around it. Honestly, I'm confident there are some very good reasons it wasn't implemented in the first place, Microsoft does a pretty good job of thinking through these things.
Upvotes: 1