[.net] Single-cast delegate?

Started by
7 comments, last by HNikolas 12 years, 7 months ago
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... :blink:

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?
Advertisement

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... :blink:

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.


Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!

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.

Why not just use a delegate and just tell people not to multi-subscribe?


Are you being sincere? :blink:


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. :mellow:

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. :D
Why do you want this, sounds weird.
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();
[size=2]Ruby on Rails, ASP.NET MVC, jQuery and everything else web.. now also trying my hand on games.

This topic is closed to new replies.

Advertisement