How to declare a singlecast delegate in C# - c#

Is there a way to declare a singlecast delegate in C#? E.g. so that it would not be possible to have more than one method referenced by the delegate at a single point in time.
I am thinking about a way to achieve flexibility in choosing what implementation to use at runtime, but with some kind of safeguard to prevent multiple actions being triggered to avoid any side-effects, especially with non-void return type delegates.

If the delegate must be an Event. (for example interface implementations etc)
You could use the custom event accessor add/remove. This only works at runtime, so this cannot be detected compiletime.
Here's an example:
private EventHandler _myHandler;
public event EventHandler MyHandler
{
add
{
if (_myHandler != null)
throw new InvalidOperationException("Only one eventhandler is supported");
_myHandler = value;
}
remove
{
// you might want to check if the delegate matches the current.
if (value == null || value == _myHandler)
_myHandler = null;
else
throw new InvalidOperationException("Unable to unregister, wrong eventhandler");
}
}
And just use it as a normal event:
MyHandler += (s, ee) => Console.WriteLine("MyHandler handler");
// if you're lazy, you could support deregistering with null
MyHandler -= null;
It's even possible to use Func<T> instead of EventHandler

You'll need to encapsulate the delegate creation and assignment. Then you can throw an exception if there are more than one handlers. Here's a trivial example
using System;
public delegate int MyDelegate(int x, int y);
public class Wrapper{
private MyDelegate d;
public Wrapper(){
this.d = null;
}
public void Assign(MyDelegate func){
if(d!= null && d.GetInvocationList().Length > 0){
throw new Exception("No more than 1 handlers allowed");
}
Console.WriteLine("Assigned");
this.d+= func;
}
}
public class Program
{
static int Sum(int x, int y)
{
return x + y;
}
static int Difference(int x, int y)
{
return x - y;
}
public static void Main()
{
Wrapper w = new Wrapper();
w.Assign(Sum);
w.Assign(Difference); //throws Exception;
}
}

Related

Adapting C# event containing ref parameter

I'm in a situation where I have to use 3rd party library that contains a lot of events and is imho not very well written. It fires up events that I have to handle in my code, but I'm trying to abstract it away (to be able to unit test rest of my code dependent on that library) so I need an adapter. The problem is that some of the events are of delegate type that take ref parameters. Here's an example of how the 3rd party library looks like:
delegate void AdapteeEventHandler1(SpecificAdaptee sender, int a, int b);
delegate void AdapteeEventHandler2(SpecificAdaptee sender, ref int a); // problematic delegate
class SpecificAdaptee
{
public event AdapteeEventHandler1 Event1;
public event AdapteeEventHandler2 Event2; // problematic event
/// <summary>Exercise Event1</summary>
public void FireEvent1()
{
Event1?.Invoke(this, 1, 2);
}
/// <summary>Exercise Event2</summary>
public void FireEvent2()
{
int a = 42;
Event2?.Invoke(this, ref a);
}
}
To show how I am abstracting regular event taking list of parameters, it contains Event1 of type AdapteeEventHandler1. The problematic type is AdapteeEventHandler2, but let me show first how I am going about adapting the whole thing:
#region AdaptedEventArgs
class AdaptedEventArgs1 : EventArgs
{
public int A { get; set; }
public int B { get; set; }
}
class AdaptedEventArgs2 : EventArgs
{
public int A { get; set; }
}
#endregion
/// <summary>These represent an abstraction layer between SpecificAdaptee and our own code</summary>
class Adaptor
{
private readonly SpecificAdaptee _specificAdaptee;
/// <summary>Maintains relationship between the event triggered by SpecificAdaptee and the adapted event.</summary>
private readonly IAdaptedEventHandlerManager _adaptedEventHandlerManager;
public Adaptor(SpecificAdaptee specificAdaptee, IAdaptedEventHandlerManager adaptedEventHandlerManager)
{
_specificAdaptee = specificAdaptee;
_adaptedEventHandlerManager = adaptedEventHandlerManager;
}
#region Events
/// <summary>Adapts SpecificAdaptee.Event1</summary>
public event EventHandler<AdaptedEventArgs1> AdaptedEvent1
{
add
{
_specificAdaptee.Event1 += _adaptedEventHandlerManager.RegisterEventHandler<AdapteeEventHandler1>(value,
(sender, a, b) => value.Invoke(this, new AdaptedEventArgs1 { A = a, B = b }));
}
remove
{
_specificAdaptee.Event1 -= _adaptedEventHandlerManager.UnregisterEventHandler<AdapteeEventHandler1>(value);
}
}
/// <summary>Adapts SpecificAdaptee.Event2</summary>
public event EventHandler<AdaptedEventArgs2> AdaptedEvent2
{
add
{
/* !!! ERROR HERE !!! */
_specificAdaptee.Event2 += _adaptedEventHandlerManager.RegisterEventHandler<AdapteeEventHandler2>(value,
(sender, a) => value.Invoke(this, new AdaptedEventArgs2 { A = a }));
}
remove
{
_specificAdaptee.Event2 -= _adaptedEventHandlerManager.UnregisterEventHandler<AdapteeEventHandler2>(value);
}
}
#endregion
}
So what is happening here is that when I register an event handler to Adaptor.AdaptedEvent1 I am wrapping EventHandler<AdaptedEventArgs1> in AdapteeEventHandler1 and register it to SpecificAdaptee.Event1, also converting the AdaptedEventArgs1 to list of parameters required by AdapteeEventHandler1. This way user can register to events of Adaptor that will be fired when SpecificAdaptee fires its own events. Next I will post a program that exercises this but note that the problem is in AdaptedEvent2, where I would like to do things in an analogous manner, but I don't know how to deal with the ref parameter (there is a syntax error in add accessor of AdaptedEvent2.
Here is a console application exercising the project:
class Program
{
public static void Main(string[] args)
{
var specific = new SpecificAdaptee();
var adapter = new Adaptor(specific, new AdaptedEventHandlerManager());
adapter.AdaptedEvent1 += OnAdaptedEvent1;
adapter.AdaptedEvent2 += OnAdaptedEvent2;
specific.FireEvent1();
specific.FireEvent2();
Console.ReadLine();
}
private static void OnAdaptedEvent1(object sender, AdaptedEventArgs1 args)
{
Console.WriteLine($"{nameof(OnAdaptedEvent1)}({sender}, {args.A}, {args.B})");
}
private static void OnAdaptedEvent2(object sender, AdaptedEventArgs2 args)
{
Console.WriteLine($"{nameof(OnAdaptedEvent2)}({sender}, {args.A})");
}
}
So that's how it's supposed to work. I register to events of my Adaptor that I have in my code, and events get fired when the 3rd party library (SpecificAdaptee) fires its own events (here in this example, triggered by calling specific.FireEvent1() and 2).
For completeness, so you can try it yourself I include code for AdaptedEventHandlerManager that maps adapted event handlers to SpecificAdaptee's handlers, so I can register and unregister multiple event handlers like I normally would do:
interface IAdaptedEventHandlerManager
{
TSpecificEventHandler RegisterEventHandler<TSpecificEventHandler>(object adaptedEventHandler,
TSpecificEventHandler specificEventHandler);
TSpecificEventHandler UnregisterEventHandler<TSpecificEventHandler>(object adaptedEventHandler)
where TSpecificEventHandler : class;
}
class AdaptedEventHandlerManager : IAdaptedEventHandlerManager
{
/// <summary>
/// Remembers relation between the specific handler and general handler. Important when unsubscribing from
/// events. Key is the general event handler we are registering to events of this class. Value are specific
/// event handlers.
/// </summary>
private readonly Dictionary<object, List<object>> _eventHandlers =
new Dictionary<object, List<object>>();
public TSpecificEventHandler RegisterEventHandler<TSpecificEventHandler>(object adaptedEventHandler,
TSpecificEventHandler specificEventHandler)
{
List<object> eventHandlerList;
if (!_eventHandlers.TryGetValue(adaptedEventHandler, out eventHandlerList))
{
eventHandlerList = new List<object> { specificEventHandler };
_eventHandlers.Add(adaptedEventHandler, eventHandlerList);
}
else
{
eventHandlerList.Add(specificEventHandler);
}
return specificEventHandler;
}
public TSpecificEventHandler UnregisterEventHandler<TSpecificEventHandler>(object adaptedEventHandler)
where TSpecificEventHandler : class
{
List<object> eventHandlerList;
if (!_eventHandlers.TryGetValue(adaptedEventHandler, out eventHandlerList))
{
return null;
}
var eventHandler = eventHandlerList.FirstOrDefault();
if (eventHandler != null)
{
eventHandlerList.Remove(eventHandler);
}
if (!eventHandlerList.Any())
{
_eventHandlers.Remove(adaptedEventHandler);
}
return eventHandler as TSpecificEventHandler;
}
}
This basically remembers in a dictionary the adapted event handler, and the list of SpecificAdaptee's handlers.
So my question: is there a way to adapt events taking ref parameters without retracting to custom delegate type that takes a ref parameter, so I can use standard EventHandler<> class with custom EventArgs descendant?
I realise it's quite a handful of code so please let me know if something is not clear. Thanks in advance.
ref parameter in the event is meant to set from the subscribers. Though it's a bad idea, the api which you're using works based on that.
You can take all the pain in the adapter class and make it work such that consumers are not polluted by the ref parameter. They can continue to use EventArgs style events.
public event EventHandler<AdaptedEventArgs2> AdaptedEvent2
{
add
{
_specificAdaptee.Event2 += _adaptedEventHandlerManager.RegisterEventHandler<AdapteeEventHandler2>(value,
(SpecificAdaptee sender, ref int a) =>
{
var args = new AdaptedEventArgs2 { A = a };
value.Invoke(this, args);
a = args.A;
});
}
remove
{
_specificAdaptee.Event2 -= _adaptedEventHandlerManager.UnregisterEventHandler<AdapteeEventHandler2>(value);
}
}
After the event is executed, we set the value of A to the ref parameter a. This simulates the behavior of ref parameter and also abstracts it under the adapter class. If A is changed in the event handler, it will be reflected in the SpecificAdaptee class too.
To show how this works like a ref parameter:
class SpecificAdaptee
{
...
public void FireEvent2()
{
int a = 42;
if (Event2 != null)
Event2(this, ref a);
Console.WriteLine("A value after the event is {0}", a);
}
}
private static void OnAdaptedEvent2(object sender, AdaptedEventArgs2 args)
{
Console.WriteLine($"{nameof(OnAdaptedEvent2)}({sender}, {args.A})");
args.A = 15;
}
This prints:
A value after the event is 15
PS: For brevity I've added only the parts of your program which needs a change.

Parametrize generic event system

I'm not sure if this has been asked before, but I really didn't know how to look for it, as I am not exactly sure what this thing / what I'm trying to do is exactly called...
I have an delegate-based messaging generic system that I use in Unity3D - taken from here.
[UA Crosslink]
It is used like this:
// Writing an event listener
void OnSpeedChanged(float speed)
{
this.speed = speed;
}
// Registering an event listener
void OnEnable()
{
Messenger<float>.AddListener("speed changed", OnSpeedChanged);
}
// Unregistering an event listener
void OnDisable()
{
Messenger<float>.RemoveListener("speed changed", OnSpeedChanged);
}
The problem I'm having, is that the code is currently very un-DRY (there's a lot of copy paste), and I want to DRY it, by hopefully parametrizing it, making it more generic.
I will post the relevant code - Please note that you don't really have to understand the code in detail and what's its doing, in order to answer.
Here's a class that does stuff behind the scene:
static internal class MessengerInternal
{
static public Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
static public readonly MessengerMode DEFAULT_MODE = MessengerMode.REQUIRE_LISTENER;
static public void OnListenerAdding(string eventType, Delegate listenerBeingAdded)
{
if (!eventTable.ContainsKey(eventType)) {
eventTable.Add(eventType, null);
}
Delegate d = eventTable[eventType];
if (d != null && d.GetType() != listenerBeingAdded.GetType()) {
throw new ListenerException(string.Format("Attempting to add listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being added has type {2}", eventType, d.GetType().Name, listenerBeingAdded.GetType().Name));
}
}
static public void OnListenerRemoving(string eventType, Delegate listenerBeingRemoved)
{
if (eventTable.ContainsKey(eventType)) {
Delegate d = eventTable[eventType];
if (d == null) {
throw new ListenerException(string.Format("Attempting to remove listener with for event type {0} but current listener is null.", eventType));
}
else if (d.GetType() != listenerBeingRemoved.GetType()) {
throw new ListenerException(string.Format("Attempting to remove listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being removed has type {2}", eventType, d.GetType().Name, listenerBeingRemoved.GetType().Name));
}
}
else {
throw new ListenerException(string.Format("Attempting to remove listener for type {0} but Messenger doesn't know about this event type.", eventType));
}
}
static public void OnListenerRemoved(string eventType)
{
if (eventTable[eventType] == null) {
eventTable.Remove(eventType);
}
}
static public void OnBroadcasting(string eventType, MessengerMode mode)
{
if (mode == MessengerMode.REQUIRE_LISTENER && !eventTable.ContainsKey(eventType)) {
throw new BroadcastException(string.Format("Broadcasting message {0} but no listener found.", eventType));
}
}
}
Now, I have generic messenger classes, that have either one, two, three or even no arguments - So the user could choose a suitable event handler to subscribe to an event.
Here's the version, that takes no generic arguments:
// No parameters
static public class Messenger {
private static Dictionary<string, Delegate> eventTable = MessengerInternal.eventTable;
static public void AddListener(string eventType, Callback handler) {
MessengerInternal.OnListenerAdding(eventType, handler);
eventTable[eventType] = (Callback)eventTable[eventType] + handler;
}
static public void RemoveListener(string eventType, Callback handler) {
MessengerInternal.OnListenerRemoving(eventType, handler);
eventTable[eventType] = (Callback)eventTable[eventType] - handler;
MessengerInternal.OnListenerRemoved(eventType);
}
static public void Broadcast(string eventType) {
Broadcast(eventType, MessengerInternal.DEFAULT_MODE);
}
static public void Broadcast(string eventType, MessengerMode mode) {
MessengerInternal.OnBroadcasting(eventType, mode);
Delegate d;
if (eventTable.TryGetValue(eventType, out d)) {
Callback callback = d as Callback;
if (callback != null) {
callback();
} else {
throw MessengerInternal.CreateBroadcastSignatureException(eventType);
}
}
}
}
Here's the version that takes one arg, (I just copy paste and add a T):
// One parameter
static public class Messenger<T> {
private static Dictionary<string, Delegate> eventTable = MessengerInternal.eventTable;
static public void AddListener(string eventType, Callback<T> handler) {
MessengerInternal.OnListenerAdding(eventType, handler);
eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler;
}
static public void RemoveListener(string eventType, Callback<T> handler) {
MessengerInternal.OnListenerRemoving(eventType, handler);
eventTable[eventType] = (Callback<T>)eventTable[eventType] - handler;
MessengerInternal.OnListenerRemoved(eventType);
}
static public void Broadcast(string eventType, T arg1) {
Broadcast(eventType, arg1, MessengerInternal.DEFAULT_MODE);
}
static public void Broadcast(string eventType, T arg1, MessengerMode mode) {
MessengerInternal.OnBroadcasting(eventType, mode);
Delegate d;
if (eventTable.TryGetValue(eventType, out d)) {
Callback<T> callback = d as Callback<T>;
if (callback != null) {
callback(arg1);
} else {
throw MessengerInternal.CreateBroadcastSignatureException(eventType);
}
}
}
}
As you might have already guessed, the one that takes two args, I just copy paste again, and add another generic type, like <T, U> etc.
This is the part that I'm trying to eliminate - But yet I have no idea how.
More accurately, what I'm looking for is: Only one Messenger class, but yet I am able to do:
Messenger<float>.Subscribe("player dead", OnDead);
Messenger<int, bool>.Subscribe("on something", OnSomething);
Messenger<bool, float, MyType>.Subscribe( stuff );
Or, (doesn't really matter which)
Messenger.Subscribe<float> ("player dead", OnDead);
You got the idea...
How can I do that, how can I write a generic messenger, that when I want to add yet another generic arg, I don't have to copy-paste and write a whole other version, just cause I needed an extra arg?
Thanks a lot!
You have a messenger but you don't seem to be sending any messages! You are trying to send the contents without a proper envelope. Wrap the values you want to send out in a class that represents your actual message and you can then subscribe to the type of the message which will contain all the values you were trying to send.
public class PlayerSpeedChangedMessage {
public Guid PlayerId { get; set; }
public int OldSpeed { get; set; }
public int NewSpeed { get; set; }
}
public class MyMessageHandler {
public MyMessageHandler() {
Messenger<PlayerSpeedChangedMessage>.Subscribe(OnDead);
}
HandleSpeedChange(PlayerSpeedChangedMessage message) {
// Do stuff with the message
}
}
I think for C# developers that Message class on the wiki is a little out-moded. C# and even Unity itself has a fairly nice messaging system already in place (As long as your needs aren't too complex). Check out SendMessage and BroadcastMessage.

Multicast delegate C#

Am studying about delegates. As I read. I learned that adding more than one function in a delegate is called multicast delegate. Based on that I wrote a program. Here two functions (AddNumbers and MultiplyNumbers) I added in the MyDelegate.
Is the below program is an example for multicast delegate ?.
public partial class MainPage : PhoneApplicationPage
{
public delegate void MyDelegate(int a, int b);
// Constructor
public MainPage()
{
InitializeComponent();
MyDelegate myDel = new MyDelegate(AddNumbers);
myDel += new MyDelegate(MultiplyNumbers);
myDel(10, 20);
}
public void AddNumbers(int x, int y)
{
int sum = x + y;
MessageBox.Show(sum.ToString());
}
public void MultiplyNumbers(int x, int y)
{
int mul = x * y;
MessageBox.Show(mul.ToString());
}
}
Yes, it's an example of a multicast delegate. Note that instead of
new MyDelegate(AddNumbers)
you can typically say just
AddNumbers
because a so-called method group conversion exists that will create the delegate instance for you.
Another thing to note is that your declaration public delegate void MyDelegate(int a, int b); does not have to reside inside another type (here inside the MainPage class). It could be a direct member of the namespace (since it's a type). But of course it's perfectly valid to "nest" it inside a class, as you do, for reasons similar to the reason why you create nested classes.
Actually all delegates in C# are MulticastDelegates, even if they only have a single method as target. (Even anonymous functions and lambdas are MulticastDelegates even though they by definition have only single target.)
MulticastDelegate is simply the base class for all kinds of function or method references in C#, whether they contain one or more targets.
So this:
MyDelegate myDel = new MyDelegate(AddNumbers);
Sets myDel to a MulticastDelegate with a single target. But this line:
myDel += new MyDelegate(MultiplyNumbers);
Updates myDel to a MulticastDelegate with two targets.
Multicast delegates is one of the feature of delegates, it wraps the reference of multiple methods and calls it sequentially and it is also known as Delegate Chaining.
Below is the example of multicast delegates.
// Declare Delegates
public delegate void MultiCast(int num1, int num2);
class Program
{
public void Add(int num1, int num2)
{
Console.WriteLine(num1 + num2);
}
public void Sub(int num1, int num2)
{
Console.WriteLine(num1 - num2);
}
public void Mul(int num1, int num2)
{
Console.WriteLine(num1 * num2);
}
static void Main(string[] args)
{
MultiCast del1, del2, del3, multAddDel, multSubDel;
del1 = new Program().Add;
del2 = new Program().Sub;
del3 = new Program().Mul;
//`There are three ways to define the multicast delegate.`
//1 way
//Adding delegates
multAddDel = del1 + del2 + del3;
multAddDel(10, 10);
//Removing Delegates
multSubDel = multAddDel - del3;
multSubDel(10, 10);
Console.WriteLine();
Console.WriteLine("Second Way");
//2 way
MultiCast multAddDel1 = null;
//Adding delegates
multAddDel1 += del1;
multAddDel1 += del2;
multAddDel1 += del3;
multAddDel1(10, 10);
//Removing Delegates
multAddDel1 -= del3;
multAddDel1(10, 10);
Console.WriteLine();
Console.WriteLine("Third Way");
//3 way
MultiCast multAddDel2 = null;
//Adding delegates
multAddDel2 = (MultiCast)Delegate.Combine(multAddDel2, del1);
multAddDel2 = (MultiCast)Delegate.Combine(multAddDel2, del2);
multAddDel2 = (MultiCast)Delegate.Combine(multAddDel2, del3);
multAddDel2(10, 10);
//Removing Delegates
multAddDel2 = (MultiCast)
Delegate.Remove(multAddDel2, del3);
multAddDel2(10, 10);
Console.ReadLine();
}
}

Why is it useful to inherit from EventArgs?

I don't understand why inheriting from EventArgs is useful.
public class ClickedEventArgs : EventArgs
{
int x;
int y;
public ClickedEventArgs (int x, int y)
{
this.x = x;
this.y = y;
}
public int X { get { return x; } }
public int Y { get { return y; } }
}
In the code above, how can I use this inheritance?
I also want to learn how I can call this code block from default.aspx
Are you asking why it's useful to derive from EventArgs in the first place? I have to say that with C# 1 it didn't make a lot of sense, because of the way delegate conversion worked - but as of C# 2 it's more sensible. It allows an event handler to be registered with an event even if it doesn't care about the details of the event arguments.
For example:
void LogEvent(object sender, EventArgs e)
{
Console.WriteLine("Event sent from " + sender);
}
...
textArea.KeyPress += LogEvent;
This works even though Control.KeyPress is an event of type KeyPressEventHandler. C# and .NET don't mind that the signature of LogEvent doesn't exactly match the signature of KeyPressEventHandler - it's compatible enough.
Admittedly this would still be feasible if we didn't have EventArgs at all (you could just use object) but given the EventArgs class and the pattern, it makes sense to derive your own event arguments from EventArgs.
What is really important here is that you can easily UPGRADE your event later to have MORE details and don't break existing decoupled listeners.
Here is a example of how you might use your code:
public class MyClass () {
public event EventHandler<ClickedEventArgs> ClickedEvent = delegate {}; //Register the event
protected void SomethingWasClicked(int x, int y) {
ClickedEvent(this, new ClickedEventArgs(x,y)); //Invoke the event that is subscribed to
}
}
public class AnotherClass () {
public AnotherClass () {
MyClass mClass = new MyClass();
mClass.ClickedEvent += new EventHandler(mClass_clickedEvent);
}
protected void mClass_clickedEvent(object sender, ClickedEventArgs e) {
//Retrieve the X parameter that was passed from the MyClass instance
int x = e.X;
}
}

Unsubscribe anonymous method in C#

Is it possible to unsubscribe an anonymous method from an event?
If I subscribe to an event like this:
void MyMethod()
{
Console.WriteLine("I did it!");
}
MyEvent += MyMethod;
I can un-subscribe like this:
MyEvent -= MyMethod;
But if I subscribe using an anonymous method:
MyEvent += delegate(){Console.WriteLine("I did it!");};
is it possible to unsubscribe this anonymous method? If so, how?
Action myDelegate = delegate(){Console.WriteLine("I did it!");};
MyEvent += myDelegate;
// .... later
MyEvent -= myDelegate;
Just keep a reference to the delegate around.
One technique is to declare a variable to hold the anonymous method which would then be available inside the anonymous method itself. This worked for me because the desired behavior was to unsubscribe after the event was handled.
Example:
MyEventHandler foo = null;
foo = delegate(object s, MyEventArgs ev)
{
Console.WriteLine("I did it!");
MyEvent -= foo;
};
MyEvent += foo;
Since C# 7.0 local functions feature has been released, the approach suggested by J c becomes really neat.
void foo(object s, MyEventArgs ev)
{
Console.WriteLine("I did it!");
MyEvent -= foo;
};
MyEvent += foo;
So, honestly, you do not have an anonymous function as a variable here. But I suppose the motivation to use it in your case can be applied to local functions.
From memory, the specification explicitly doesn't guarantee the behaviour either way when it comes to equivalence of delegates created with anonymous methods.
If you need to unsubscribe, you should either use a "normal" method or retain the delegate somewhere else so you can unsubscribe with exactly the same delegate you used to subscribe.
In 3.0 can be shortened to:
MyHandler myDelegate = ()=>Console.WriteLine("I did it!");
MyEvent += myDelegate;
...
MyEvent -= myDelegate;
Instead of keeping a reference to any delegate you can instrument your class in order to give the event's invocation list back to the caller. Basically you can write something like this (assuming that MyEvent is declared inside MyClass):
public class MyClass
{
public event EventHandler MyEvent;
public IEnumerable<EventHandler> GetMyEventHandlers()
{
return from d in MyEvent.GetInvocationList()
select (EventHandler)d;
}
}
So you can access the whole invocation list from outside MyClass and unsubscribe any handler you want. For instance:
myClass.MyEvent -= myClass.GetMyEventHandlers().Last();
I've written a full post about this tecnique here.
Kind of lame approach:
public class SomeClass
{
private readonly IList<Action> _eventList = new List<Action>();
...
public event Action OnDoSomething
{
add {
_eventList.Add(value);
}
remove {
_eventList.Remove(value);
}
}
}
Override the event add/remove methods.
Keep a list of those event handlers.
When needed, clear them all and re-add the others.
This may not work or be the most efficient method, but should get the job done.
If you want to be able to control unsubscription then you need to go the route indicated in your accepted answer. However, if you are just concerned about clearing up references when your subscribing class goes out of scope, then there is another (slightly convoluted) solution which involves using weak references. I've just posted a question and answer on this topic.
One simple solution:
just pass the eventhandle variable as parameter to itself.
Event if you have the case that you cannot access the original created variable because of multithreading, you can use this:
MyEventHandler foo = null;
foo = (s, ev, mehi) => MyMethod(s, ev, foo);
MyEvent += foo;
void MyMethod(object s, MyEventArgs ev, MyEventHandler myEventHandlerInstance)
{
MyEvent -= myEventHandlerInstance;
Console.WriteLine("I did it!");
}
If the best way is to keep a reference on the subscribed eventHandler, this can be achieved using a Dictionary.
In this example, I have to use a anonymous method to include the mergeColumn parameter for a set of DataGridViews.
Using the MergeColumn method with the enable parameter set to true enables the event while using it with false disables it.
static Dictionary<DataGridView, PaintEventHandler> subscriptions = new Dictionary<DataGridView, PaintEventHandler>();
public static void MergeColumns(this DataGridView dg, bool enable, params ColumnGroup[] mergedColumns) {
if(enable) {
subscriptions[dg] = (s, e) => Dg_Paint(s, e, mergedColumns);
dg.Paint += subscriptions[dg];
}
else {
if(subscriptions.ContainsKey(dg)) {
dg.Paint -= subscriptions[dg];
subscriptions.Remove(dg);
}
}
}
if you want refer to some object with this delegate, may be you can use Delegate.CreateDelegate(Type, Object target, MethodInfo methodInfo)
.net consider the delegate equals by target and methodInfo
There is a way to solve this by implementing the closure yourself instead of a lambda expression.
Assume that the class to be used as a capture variable is as follows.
public class A
{
public void DoSomething()
{
...
}
}
public class B
{
public void DoSomething()
{
...
}
}
public class C
{
public void DoSomething()
{
...
}
}
These classes will be used as capture variables, so we instantiate them.
A a = new A();
B b = new B();
C c = new C();
Implement the closure class as shown below.
private class EventHandlerClosure
{
public A a;
public B b;
public C c;
public event EventHandler Finished;
public void MyMethod(object, MyEventArgs args)
{
a.DoSomething();
b.DoSomething();
c.DoSomething();
Console.WriteLine("I did it!");
Finished?.Invoke(this, EventArgs.Empty);
}
}
Instantiate the closure class, create a handler, then subscribe to the event and subscribe to the lambda expression that unsubscribes from the closure class's Finished event.
var closure = new EventHandlerClosure
{
a = a,
b = b,
c = c
};
var handler = new MyEventHandler(closure.MyMethod);
MyEvent += handler;
closure.Finished += (s, e)
{
MyEvent -= handler;
}
I discovered this quite old thread recently for a C# project and found all the answers very useful. However, there was one aspect that didn't work well for my particular use case - they all put the burden of unsubscribing from an event on the subscriber. I understand that one could make the argument that it's the subscribers job to handle this, however that isn't realistic for my project.
My primary use case for events is for listening to timers to sequence animations (it's a game). In this scenario, I use a lot of anonymous delegates to chain together sequences. Storing a reference to these isn't very practical.
In order to solve this, I've created a wrapper class around an event that lets you subscribe for a single invocation.
internal class EventWrapper<TEventArgs> {
private event EventHandler<TEventArgs> Event;
private readonly HashSet<EventHandler<TEventArgs>> _subscribeOnces;
internal EventWrapper() {
_subscribeOnces = new HashSet<EventHandler<TEventArgs>>();
}
internal void Subscribe(EventHandler<TEventArgs> eventHandler) {
Event += eventHandler;
}
internal void SubscribeOnce(EventHandler<TEventArgs> eventHandler) {
_subscribeOnces.Add(eventHandler);
Event += eventHandler;
}
internal void Unsubscribe(EventHandler<TEventArgs> eventHandler) {
Event -= eventHandler;
}
internal void UnsubscribeAll() {
foreach (EventHandler<TEventArgs> eventHandler in Event?.GetInvocationList()) {
Event -= eventHandler;
}
}
internal void Invoke(Object sender, TEventArgs e) {
Event?.Invoke(sender, e);
if(_subscribeOnces.Count > 0) {
foreach (EventHandler<TEventArgs> eventHandler in _subscribeOnces) {
Event -= eventHandler;
}
_subscribeOnces.Clear();
}
}
internal void Remove() {
UnsubscribeAll();
_subscribeOnces.Clear();
}
}
The side benefit of having this in a class is that you can make it private and expose only the functionality you want. For example, only expose the SubscribeOnce (and not the Subscribe) method.
public class MyClass {
private EventWrapper<MyEventEventArgs> myEvent = new EventWrapper<MyEventEventArgs>();
public void FireMyEvent() {
myEvent.Invoke(this, new MyEventEventArgs(1000, DateTime.Now));
}
public void SubscribeOnce(EventHandler<MyEventEventArgs> eventHandler) {
myEvent.SubscribeOnce(eventHandler);
}
public class MyEventEventArgs : EventArgs {
public int MyInt;
public DateTime MyDateTime;
public MyEventEventArgs(int myInt, DateTime myDateTime) {
MyInt = myInt;
MyDateTime = myDateTime;
}
}
}
The tradeoff here is more overhead for having an instance of this for each event, however in my scenario - this is an acceptable tradeoff to ensure that garbage gets collected efficiently and the code is more maintainable on the subscriber side. Full example here.
Here is a simple solution, which removes all assigned methods from an event. Also anonymous methods.
Use this code and adjust the names.
if (MyEvent != null)
foreach (Delegate del in MyEvent.GetInvocationList())
MyEvent -= (EventHandler<MyEventHandlerType>)del;
Example usage
public class SomeClass
{
public event EventHandler<NiceEventArgs> NiceEvent;
public void RemoveHandlers()
{
if (NiceEvent != null)
foreach (Delegate del in NiceEvent.GetInvocationList())
NiceEvent -= (EventHandler<NiceEventArgs>)del;
}
}
Thanks to hemme's answer, which I used as inspiration.

Categories