All this time I thought delegates were single-cast, and that events were essentially a list of delegates (allowing for multi-cast). Well, today I learned that you could use the += operator on a delegate!
As can be expected, this knocked me off my chair...
I dug into the theory a bit, and found that the 'delegate' keyword essentially used 'System.MulticastDelegate', and that 'System.Delegate' was a single-cast delegate.
System.Object
->System.Delegate
->->System.MulticastDelegate
However, according to MSDN, I'm not allowed to use System.Delegate (it's a "special class" to be used only by the compiler). So what's the standard way to get a single-cast delegate?
[.net] Single-cast delegate?
All this time I thought delegates were single-cast, and that events were essentially a list of delegates (allowing for multi-cast). Well, today I learned that you could use the += operator on a delegate!
As can be expected, this knocked me off my chair...
I dug into the theory a bit, and found that the 'delegate' keyword essentially used 'System.MulticastDelegate', and that 'System.Delegate' was a single-cast delegate.
System.Object
->System.Delegate
->->System.MulticastDelegate
However, according to MSDN, I'm not allowed to use System.Delegate (it's a "special class" to be used only by the compiler). So what's the standard way to get a single-cast delegate?
use Action (for a delegate method not returning any value) or Func( for one which does). There are generic overloads for 0..8 paramaters in each case. A delegate seems to be an array of Action.
use Action (for a delegate method not returning any value) or Func( for one which does). There are generic overloads for 0..8 paramaters in each case. A delegate seems to be an array of Action.
Are there any alternatives that can be used when .NET 2.0 is the target framework? Func is purely .NET 3.5+, and Action is only .NET 2.0 if you only use 1 parameter (0,2+ are all .NET 3.5+).
I might be able to get by with Action (single parameter and no return type), but it won't be pretty...
Why not just use a delegate and just tell people not to multi-subscribe? If you need a return value, store it in the EventArgs (examine how the CancelEventArgs pattern works).
The better option would be to upgrade to C# 3.0+ and .Net 3.5+; the new features make functional programming much easier.
The better option would be to upgrade to C# 3.0+ and .Net 3.5+; the new features make functional programming much easier.
Why not just use a delegate and just tell people not to multi-subscribe?
Are you being sincere?
If you need a return value, store it in the EventArgs (examine how the CancelEventArgs pattern works).
Yah, that's what I had in mind; the KeyPressEventArts from Windows.Forms uses a 'Handled' property that has identical functionality to the 'bool' that would have normally been my return value.
use Action (for a delegate method not returning any value) or Func( for one which does). There are generic overloads for 0..8 paramaters in each case. A delegate seems to be an array of Action.
This does not prevent multi-assignment. They're still delegates and as such are multicast.
The only way you're going to be able to provide a single-cast delegate is by wrapping it in a class which does assignment to the delegate and re-exposes some calling mechanism. That's going to be awkward to write and more awkward to use.
Why exactly do you need to prevent mutlicasting? A user can simply do:
del = delegate(){ a(); b(); };
instead of
del += a;
del += b;
The only way you're going to be able to provide a single-cast delegate is by wrapping it in a class which does assignment to the delegate and re-exposes some calling mechanism. That's going to be awkward to write and more awkward to use.
Agreed; if I can't do this cleanly with a delegate, I wonder if I could solve this with an interface.
For instance, instead of a delegate based design:
[source lang=csharp]
SwimmingPool swimpool = new SwimmingPool();
swimpool.Overflow = new OverflowDelegate(PoolOverflowed);
swimpool.Overflow += PoolOverflowed; /* attempting to prevent this
(user may be tempted to write this in later files, without realizing they don't have to!) */
[/source]
To replace the delegate with just an interface that would get called:
[source lang=csharp]
SwimmingPool swimpool = new SwimmingPool();
swimpool.IOverflow= this; /* no temptation to "+=" later, though in my
situation this should never get changed after it has been set -- and yet it still can be! */
[/source]
Hmmm, maybe if I made it readonly; SwimmingPool(IOverflow overflow)...
[source lang=csharp]
SwimmingPool swimpool = new SwimmingPool(this);
// swimpool.IOverflow = this; // <-- would not compile =D
[/source]
Alright, I think I've got a work-around.
I would create a wrapper class around the delegate.
public class SingleDelegate
{
public delegate void MyDelegate();
private MyDelegate invocation;
public MyDelegate Invocation
{
get
{
return invocation;
}
set
{
if (invocation == null)
{
invocation = value;
}
else
{
// Re-assign, leave aside or something else.
}
}
}
}
SingleDelegate m = new SingleDelegate() { Invocation = MyFunc };
m.Invocation();
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement