Questions About Delegates

F

Frankie

The following questions are with respect to this delegate declaration:

delegate void MyDelegate(string s);

Question 1:
Why does the following NOT work? Why can't I just create a new instance of
MyDelegate that references zero methods?

MyDelegate d;
d = new MyDelegate();


Question 2:
Given that the following code successfully registers two methods with the
MyDelegate instance...

MyDelegate d = new MyDelegate(MyMethod)
d += new MyDelegate(MyOtherMethod);

.... why do we have to register the additional method (MyOtherMethod) via a
NEW MyDelegate instance? The above code (d += new MyDelegate...) makes it so
we are adding an instance of a delegate to an instance of a delegate. When
our objective is "simply to register an additional method with a delegate
instance" why can we not simply do something like:

d.Add(MyOtherMethod); // I know, there is no Add method - but why not?
or
d += MyOtherMethod;

I thought that delegates maintained an internal linked list of "methods to
call" - I would therefore expect a simple .Add() method that lets us add
method references to a delegate instance.


Question 3:
When we want to remove a method reference from a delegate, we still must use
the 'new' keyword, like this:

d -= new MyDelegate(MyMethod);

Why do we have to use the 'new' keyword when UNregistering a method
reference?

Thanks!
 
J

Jon Skeet [C# MVP]

The following questions are with respect to this delegate declaration:

delegate void MyDelegate(string s);

Question 1:
Why does the following NOT work? Why can't I just create a new instance of
MyDelegate that references zero methods?

For better or worse, delegate instance always references one or more
methods. The null reference ends up being used for 0 methods (e.g.
"subtracting" one delegate from another will return null if the result
is a no-op).

In C# 2, it's easy to create an effectivey no-op delegate instance
(for any delegate type which has no return type and no out
parameters):

MyDelegate d = delegate { };
Question 2:
Given that the following code successfully registers two methods with the
MyDelegate instance...

MyDelegate d = new MyDelegate(MyMethod)
d += new MyDelegate(MyOtherMethod);

... why do we have to register the additional method (MyOtherMethod) via a
NEW MyDelegate instance?

Delegates are immutable. You always need a new instance in order to
combine one with another.
The above code (d += new MyDelegate...) makes it so
we are adding an instance of a delegate to an instance of a delegate.

Yes - and the result is another delegate instance.
When
our objective is "simply to register an additional method with a delegate
instance" why can we not simply do something like:

You can't "register an additional method" because delegate instances
themselves are immutable.

d.Add(MyOtherMethod); // I know, there is no Add method - but why not?
or
d += MyOtherMethod;

The latter works in C# 2.
I thought that delegates maintained an internal linked list of "methods to
call" - I would therefore expect a simple .Add() method that lets us add
method references to a delegate instance.

That would make sense if delegates were mutable. Like strings, they're
not. (Personally I think that's a good thing in general.)
Question 3:
When we want to remove a method reference from a delegate, we still must use
the 'new' keyword, like this:

d -= new MyDelegate(MyMethod);

Why do we have to use the 'new' keyword when UNregistering a method
reference?

Same answer as question 2.

Jon
 
N

Nicholas Paldino [.NET/C# MVP]

Frankie,

See inline:
The following questions are with respect to this delegate declaration:

delegate void MyDelegate(string s);

Question 1:
Why does the following NOT work? Why can't I just create a new instance of
MyDelegate that references zero methods?

MyDelegate d;
d = new MyDelegate();

Well, d assigned to null will give you what you want, like so:

MyDelegate d = null;

If you don't give it a method to point to, then what good is the
instance?
Question 2:
Given that the following code successfully registers two methods with the
MyDelegate instance...

MyDelegate d = new MyDelegate(MyMethod)
d += new MyDelegate(MyOtherMethod);

... why do we have to register the additional method (MyOtherMethod) via a
NEW MyDelegate instance? The above code (d += new MyDelegate...) makes it
so we are adding an instance of a delegate to an instance of a delegate.
When our objective is "simply to register an additional method with a
delegate instance" why can we not simply do something like:

d.Add(MyOtherMethod); // I know, there is no Add method - but why not?
or
d += MyOtherMethod;

I thought that delegates maintained an internal linked list of "methods to
call" - I would therefore expect a simple .Add() method that lets us add
method references to a delegate instance.

They do reference an internal linked list, but those linked list
instances are Delegate instances themselves which you can get through the
GetInvocationList method. The call to += is really just a call to the
Combine method (ultimately, maybe through some redirection) which takes two
instances of a Delegate.

The point here is that the delegate is an instance of an object. The
method itself is just that, a method, you need a delegate instance to work
with in order to do anything.
Question 3:
When we want to remove a method reference from a delegate, we still must
use the 'new' keyword, like this:

d -= new MyDelegate(MyMethod);

Why do we have to use the 'new' keyword when UNregistering a method
reference?

The same reason you need a new instance of the delegate when using +=,
as the call to -= is a call to Remove.
 
B

Brian Gideon

The following questions are with respect to this delegate declaration:

delegate void MyDelegate(string s);

Question 1:
Why does the following NOT work? Why can't I just create a new instance of
MyDelegate that references zero methods?

MyDelegate d;
d = new MyDelegate();

It wouldn't make sense to have a delegate instance that points to
nothing.
Question 2:
Given that the following code successfully registers two methods with the
MyDelegate instance...

MyDelegate d = new MyDelegate(MyMethod)
d += new MyDelegate(MyOtherMethod);

... why do we have to register the additional method (MyOtherMethod) via a
NEW MyDelegate instance? The above code (d += new MyDelegate...) makes it so
we are adding an instance of a delegate to an instance of a delegate. When
our objective is "simply to register an additional method with a delegate
instance" why can we not simply do something like:

d.Add(MyOtherMethod); // I know, there is no Add method - but why not?
or
d += MyOtherMethod;

I thought that delegates maintained an internal linked list of "methods to
call" - I would therefore expect a simple .Add() method that lets us add
method references to a delegate instance.

No, you aren't adding another target to the current instance.
Delegates cannot accept additional "registrations" after they are
created because they are immutable. The += operator creates a new
delegate instance that is a composite of the current delegates
invocation list plus the new target you want to add.

Perhaps the designers felt there would be confusion because most
(all?) of the Add methods in the BCL effect the current instance. So
having an Add method that behaved like...say...the String.Replace
method would be weird.
Question 3:
When we want to remove a method reference from a delegate, we still must use
the 'new' keyword, like this:

d -= new MyDelegate(MyMethod);

Why do we have to use the 'new' keyword when UNregistering a method
reference?

I presume the designers wanted the remove operation to be similar,
semantically anyway, to the add operation so that was a natural
choice.
 
F

Frankie

Thanks all. I was missing the fact that delegates are immutable.

Brian and Nicholas questioned my first question...

<< It wouldn't make sense to have a delegate instance that points to
nothing>>
and
<< If you don't give it a method to point to, then what good is the
instance? >>

First, the question was more theoretical in nature.

Second, it is not unusual to create an instance of some object, and then
later give it meaning. Sometimes we want to create object variables in one
location (perhaps at a higher scope), and then set it to something
meaningful later.

-Frankie
 
P

Peter Duniho

Frankie said:
[...]
Second, it is not unusual to create an instance of some object, and then
later give it meaning. Sometimes we want to create object variables in one
location (perhaps at a higher scope), and then set it to something
meaningful later.

That's true. And typically you'd do that by declaring the variable of
the type of interest, but letting the default initialization of "null"
take place. Then you set the variable to some instance later. It's
quite common to do what you describe; but I can't recall seeing it done
in the _way_ that you expect delegate to do it.

Likewise with the delegate type. You can in fact declare a _variable_
of that type, without setting it to anything. But it doesn't make sense
to have an _instance_ of that type that doesn't refer to anything,
mainly because the semantics of the type imply that if it's non-null you
can execute it.

As Jon said, you can create a simple "nop" instance of a delegate, but
you can't have a delegate instance that refers to nothing. You might as
well just have the delegate variable refer to "null" in that case.

Which is, in fact, how you do it in pretty much any other class. For
example, how would you construct a Form instance that doesn't actually
encapsulate an actual Form?

Pete
 
M

Matt Brunell

Question 3:
When we want to remove a method reference from a delegate, we still must
use the 'new' keyword, like this:

d -= new MyDelegate(MyMethod);

Why do we have to use the 'new' keyword when UNregistering a method
reference?

You don't have to use the 'new' keyword to unregister a method reference.
I've done this before:

EventHandler m_handler = new EventHandler(HandleEvent);

this.Click += m_handler;
....
// remove event handler
this.Click -= m_handler;

// which is equivalent to
this.Click -= new EventHandler(HandleEvent);
....

I think that from a semantic point of view, the 'new' syntax didn't make
sense to me. I mean, delegates are reference types, right? So, removing a
'new' instance wouldn't accomplish anything. But, because they are
immutable, reference equality is overriden to behave like value equality (
just like strings ). You could consider the 'new' delegate removal syntax
handy because you don't have to keep a delegate instance around in your
class if you want to attatch, and detatch from an event.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top