Proper use of delegates.

R

Roger Frost

Since we are currently on the subject of multi-threading in a different
thread, I have a question about delegates.

When I use delegates, I just create one for each different parameter set
that I need.

For example:

delegate void callBackString(string d_string);

delegate void callBackStringArray(string[] d_string);

delegate void callBackInt(int d_int);

delegate void callBackSB(string d_string, bool d_bool);



....And then I just reuse them when and where I need them.

Is this the proper way to use delegates?

I'm highly interested in the most efficient way if this isn't it.

Thanks
 
J

Jon Skeet [C# MVP]

Roger Frost said:
Since we are currently on the subject of multi-threading in a different
thread, I have a question about delegates.

When I use delegates, I just create one for each different parameter set
that I need.

For example:

delegate void callBackString(string d_string);

delegate void callBackStringArray(string[] d_string);

delegate void callBackInt(int d_int);

delegate void callBackSB(string d_string, bool d_bool);

...And then I just reuse them when and where I need them.

Is this the proper way to use delegates?

I'm highly interested in the most efficient way if this isn't it.

1) You're declaring a type, so use the normal convention for type
names: Pascal case.

2) If you're using .NET 3.5 you can use the built-in Action<...>
delegates; your delegates above are equivalent to

Action<string>
Action<string[]>
Action<int>
Action<string,bool>

3) If you're using .NET 2 you can declare your own Action<...>
delegates to make point 2 work.

4) If you're using .NET 1.1, you're stuck with the approach you've
already got.
 
M

Marc Gravell

Generics - but it is already done for you: consider Action<T>?
i.e. Action<string>, Action<string[]> and Action<int> etc match your first 3
examples

..NET 3.5 introduces multi-paramater variants:
Action<string,bool> matches your last example

If the delegate should return a value, then Func<...> is also available -
i.e.
"int Foo(string arg)" would match Func<string,int>

Marc
 
R

Roger Frost

Jon Skeet said:
1) You're declaring a type, so use the normal convention for type
names: Pascal case.

Conventions are something that I struggle with and hope to get better at.
When it is just me writing programs, it's not a problem, but I know that I
need to learn the standards...and I appreciate having my mistakes pointed
out.
2) If you're using .NET 3.5 you can use the built-in Action<...>
delegates; your delegates above are equivalent to

Action<string>
Action<string[]>
Action<int>
Action<string,bool>

Yup .NET 3.5, I will optimize my code for this.

Thanks!
 
P

Peter Duniho

Since we are currently on the subject of multi-threading in a different
thread, I have a question about delegates.

When I use delegates, I just create one for each different parameter set
that I need.

[...]
...And then I just reuse them when and where I need them.

Is this the proper way to use delegates?

Well, for single-parameter delegates that return void, you could just use
the generic Action<T> delegate. So, for example, where you'd declare and
use "delegate void callBackString(string d_string)", you'd skip the
declaration and just use "Action<string>" instead where you would have
used "callBackString" as the type. There's also a no-parameter delegate
named Action. Non-generic, obviously.

If you're using .NET 3.5, they've added two, three, and four-parameter
versions of the same generic type. If you need more than four parameters,
then you might consider declaring a single generic delegate type for each
parameter count you need that you reuse as necessary, rather than making a
new one for each more-than-four-parameter action you have.

For example:

delegate void Action<T1, T2, T3, T4, T5>(T1 t1, T2 t2, T3 t3, T4
t4, T5 t5);

Of course, if you've got more than four parameters for an action, you may
have other issues. But at least you can avoid making all those delegate
types. :)

If you're not using .NET 3.5, then you could of course declare the two-,
three-, and four-parameter Action delegate types yourself, as with the
five-parameter example above (except with fewer parameters, of course :) ).

Pete
 
R

Roger Frost

Thanks to everyone for the help...here is what I have now:

private void populateListViews(string[] fileList)
{//Addes the file(s) to the correct ListView Queues.

//Handle calls from a different thread.
if (InvokeRequired)
{//Caller is on a different thread.

//Create a new delegate.
Action<string[]> cb = new
Action<string[]>(populateListViews);

//Invoke the delegate on the owner thread.
Invoke(cb, new object[] { fileList });
}
else
{//Caller is on this thread.
//The good stuff.
}

Is this the Proper use of delegates in .NET 3.5?

If so, can I get a brief run down of what I am gaining over:

delegate void CallBackStringArray(string[] d_string);

[...]

CallBackString cb = new CallBackString(populateListViews);

Invoke(cb, new object[] { fileList });


While we are here, how are my conventions in these examples?



Peter Duniho said:
Since we are currently on the subject of multi-threading in a different
thread, I have a question about delegates.

When I use delegates, I just create one for each different parameter set
that I need.

[...]
...And then I just reuse them when and where I need them.

Is this the proper way to use delegates?

Well, for single-parameter delegates that return void, you could just use
the generic Action<T> delegate. So, for example, where you'd declare and
use "delegate void callBackString(string d_string)", you'd skip the
declaration and just use "Action<string>" instead where you would have
used "callBackString" as the type. There's also a no-parameter delegate
named Action. Non-generic, obviously.

If you're using .NET 3.5, they've added two, three, and four-parameter
versions of the same generic type. If you need more than four parameters,
then you might consider declaring a single generic delegate type for each
parameter count you need that you reuse as necessary, rather than making a
new one for each more-than-four-parameter action you have.

For example:

delegate void Action<T1, T2, T3, T4, T5>(T1 t1, T2 t2, T3 t3, T4
t4, T5 t5);

Of course, if you've got more than four parameters for an action, you may
have other issues. But at least you can avoid making all those delegate
types. :)

If you're not using .NET 3.5, then you could of course declare the two-,
three-, and four-parameter Action delegate types yourself, as with the
five-parameter example above (except with fewer parameters, of course
:) ).

Pete
 
J

Jon Skeet [C# MVP]

Roger Frost said:
Thanks to everyone for the help...here is what I have now:

private void populateListViews(string[] fileList)
{//Addes the file(s) to the correct ListView Queues.

//Handle calls from a different thread.
if (InvokeRequired)
{//Caller is on a different thread.

//Create a new delegate.
Action<string[]> cb = new
Action<string[]>(populateListViews);

//Invoke the delegate on the owner thread.
Invoke(cb, new object[] { fileList });
}
else
{//Caller is on this thread.
//The good stuff.
}

Is this the Proper use of delegates in .NET 3.5?

Well, it should certainly work. You don't need to declare the variable
first, and you can just cast to Action<string[]>, giving:

if (InvokeRequired)
{
Invoke ((Action<string>[]) populateListViews, fileList);
}
else
{
...
}
If so, can I get a brief run down of what I am gaining over:

delegate void CallBackStringArray(string[] d_string);

[...]

CallBackString cb = new CallBackString(populateListViews);

Invoke(cb, new object[] { fileList });

You're avoiding having to declare your own delegate.
While we are here, how are my conventions in these examples?

Your method is still in camel case instead of Pascal case, and I'd use
XML comments (above the method) instead of the "Adds the file(s) to the
correct ListView queues" comment being inside the brace. Other than
that it looks okay.
 
R

Roger Frost

I really appreciate everyone taking the time to help. I have a problem
using Jon's example with my string array methods...



Jon Skeet said:
[...] You don't need to declare the variable
first, and you can just cast to Action<string[]>, giving:

if (InvokeRequired)
{
Invoke ((Action<string>[]) populateListViews, fileList);
}
else
{
...
}
First of all

Invoke((Action<string>)writeStatus, newMsg);

Works fine on my string method, no problem what so ever.

But...

Invoke((Action<string>[])populateListViews, fileList);

Doesn't compile, 3 errors:

1) Cannot convert method group 'populateListViews' to non-delegate type
'System.Action<string>[]'. Did you intend to invoke the method?

2) The best overloaded method match for
'System.Windows.Forms.Control.Invoke(System.Delegate, params object[])' has
some invalid arguments.

(My method populateListViews isn't overloaded, by the way)

3) Argument '1': cannot convert from 'System.Action<string>[]' to
'System.Delegate'



If I change it to:

Invoke((Action<string[]>)populateListViews, fileList);

(Which is what I think Jon meant in the first place, as far as I can tell
due to the compile time errors above.)

It compiles fine, but at run time I get a "Parameter count mismatch." logic
error.

My method is: private void populateListViews(string[] fileList){...}

And the call is: populateListViews(Directory.GetFiles(folderPath));

Directory.GetFiles() returns string[], and my logic was fine when I was
declaring my own delegate or Action<string[]> cb = new
Action<string[]>(populateListViews);


I have tried several different combinations, some compiled and some didn't,
but the ones that compiled always raise that same logic error. What am I
missing?
 
J

Jon Skeet [C# MVP]

Roger Frost said:
I really appreciate everyone taking the time to help. I have a problem
using Jon's example with my string array methods...

Oops, yes.

If I change it to:

Invoke((Action<string[]>)populateListViews, fileList);

(Which is what I think Jon meant in the first place, as far as I can tell
due to the compile time errors above.)

Yes indeed.
It compiles fine, but at run time I get a "Parameter count mismatch." logic
error.

My method is: private void populateListViews(string[] fileList){...}

And the call is: populateListViews(Directory.GetFiles(folderPath));

Directory.GetFiles() returns string[], and my logic was fine when I was
declaring my own delegate or Action<string[]> cb = new
Action<string[]>(populateListViews);

I have tried several different combinations, some compiled and some didn't,
but the ones that compiled always raise that same logic error. What am I
missing?

Ooh, that's a subtle one. It's converting string[] into object[], and
passing it as if the method took lots of string parameters.

Cast fileList to object, so it'll be treated as one parameter, and I
think you'll be okay:

Invoke((Action<string[]>)populateListViews, (object)fileList);

Basically you want to make the compiler create a new object[] with a
single element (your string[]).
 
R

Roger Frost

Brilliant! Can I, for the sake of future program changes, always cast my
arguments to objects even if they aren't arrays?

I tested it and it works, but is this considered poor practice?

My guess is it is considered good programming...

Thanks Jon.

Jon Skeet said:
Roger Frost said:
I really appreciate everyone taking the time to help. I have a problem
using Jon's example with my string array methods...

Oops, yes.

If I change it to:

Invoke((Action<string[]>)populateListViews, fileList);

(Which is what I think Jon meant in the first place, as far as I can tell
due to the compile time errors above.)

Yes indeed.
It compiles fine, but at run time I get a "Parameter count mismatch."
logic
error.

My method is: private void populateListViews(string[] fileList){...}

And the call is: populateListViews(Directory.GetFiles(folderPath));

Directory.GetFiles() returns string[], and my logic was fine when I was
declaring my own delegate or Action<string[]> cb = new
Action<string[]>(populateListViews);

I have tried several different combinations, some compiled and some
didn't,
but the ones that compiled always raise that same logic error. What am I
missing?

Ooh, that's a subtle one. It's converting string[] into object[], and
passing it as if the method took lots of string parameters.

Cast fileList to object, so it'll be treated as one parameter, and I
think you'll be okay:

Invoke((Action<string[]>)populateListViews, (object)fileList);

Basically you want to make the compiler create a new object[] with a
single element (your string[]).
 
P

Peter Duniho

Brilliant! Can I, for the sake of future program changes, always cast
my arguments to objects even if they aren't arrays?

Yes. (Apparently) the compiler will do it for you as long what you're
passing doesn't look like an object[] to the compiler (as it did when
before you were casting). But any time you don't need to pass an array of
parameters, yes...you could explicitly do the cast just to make sure that
the overload you want is the one that's actually used.

I wrote "apparently", because I wasn't even aware that you could do this.
Control.Invoke() only has two overloads, neither of which allow a simple
object instance as the second parameter. I assume that there's some
compiler "funny business" going on that allows a simple object instance to
be automatically converted to the required object[] needed by Invoke().
But I don't know what that is.

Maybe Jon can elaborate on why this works.
I tested it and it works, but is this considered poor practice?

Well, I don't know about "poor". But the overload that is actually going
to be more broadly useful is the one that takes an object[] as the second
parameter. IMHO, if you're looking for a pattern to use consistently, for
every time you use the Control.Invoke() method, it would be better to go
with that overload. Then, what you're passing is always an object[], with
some number of elements equal to the number of parameters for the method.

While the approach you're asking about works only in a very specific
scenario, the other overload works in all scenarios. It works for single
parameters, multiple parameters, and it works when the parameters are
"ref" or "out" as well. So if you get into the habit of always passing an
object[] to Invoke() when there are parameters, putting each actual
parameter as an element in that array, then it will always work and you'll
always avoid the issue you ran into here. For example:

Invoke((Action<string[]>)populateListViews, new object[] { fileList });

It's not quite as pretty as just casting a single parameter to object, but
it's something that is more broadly useful.
My guess is it is considered good programming...

Well, given that Jon suggested it, I'd certainly hesitate to call it bad
programming. :) But I do think there's a good reason to go with the
alternative consistent pattern I describe above.

I certainly wouldn't object to code that casts to object though, in
situations where it's appropriate.

Pete
 
J

jehugaleahsa

To be honest, I preferred you earlier example. I believe a delegate
should be named after what it is doing, not given a generic name based
on its parameters and return type. It is convenient to use built-in
delegates, but do they tell readers anything? Look at
Converter<TInput, TOutput>, it is one of the most useful delegate
definitions out there - it take something, it returns something. But,
if I'm not converting anything, why am I adding my method name into
it?

I say, using 3.0's delegates is fine because, well, you are forced to
(and they usually make sense). However, especially when doing UI
threading delegates, make as many delegates as you need so that
delegate names make sense. It is no different than finding good names
for any other variable.

I'm not sure why not to use better names and why anyone would suggest
replacing a good name with a more generic one.

IMHO,
Travis
 
R

Roger Frost

I am not completely sure which post this was in reply to.


To be honest, I preferred you earlier example. I believe a delegate
should be named after what it is doing, not given a generic name based
on its parameters and return type. It is convenient to use built-in
delegates, but do they tell readers anything? Look at
Converter<TInput, TOutput>, it is one of the most useful delegate
definitions out there - it take something, it returns something. But,
if I'm not converting anything, why am I adding my method name into
it?



"Earlier example" refers to:

delegate void callBackString(string d_string);

or:

Action<string> cb = new Action<string>(populateListViews);

??? I'm assuming the first, since it is "named after what it is doing."


I say, using 3.0's delegates is fine because, well, you are forced to
(and they usually make sense). However, especially when doing UI
threading delegates, make as many delegates as you need so that
delegate names make sense. It is no different than finding good names
for any other variable.

But if I'm just doing UI threading delegates, all I'm looking for is a call
from the current thread back to the same method. I won't be creating two
different delegates for two methods if they both take the same parameter and
return the same type. Or are you suggesting, for readability, that each
method has its own unique delegate?

I believe that even from a reader's standpoint it is easy enough to
understand with the generics for call back purposes.


I'm not sure why not to use better names and why anyone would suggest
replacing a good name with a more generic one.

This all began with my curiosity about common practices, more or less.

My major question in the whole delegates debate now is, from a system
resources stand point, are generics better?

There is usually a tradeoff in programming debates, and I am not savvy
enough to know the cost of:

delegate void callBackString(string d_string);

vs.:

Action<string> cb = new Action<string>(populateListViews);

vs. just skipping the declaration and going straight to:

Invoke((Action<string[]>)populateListViews, (object)fileList);

I am assuming that a similar amount of resources are used in all three
cases, just in the later the compiler handle's more of the details.

Thanks for the comment, I have learned quite a bit since the beginning of
this message thread and I look forward to gaining even more understanding.

I am completely open to all suggestions and opinions.
 
J

Jon Skeet [C# MVP]

I say, using 3.0's delegates is fine because, well, you are forced to
(and they usually make sense). However, especially when doing UI
threading delegates, make as many delegates as you need so that
delegate names make sense. It is no different than finding good names
for any other variable.

And when it comes naming *variables*, that's fine. By all means name
delegate *variables* according to what they do. But declaring an extra
type all the time seems pointless to me.
I'm not sure why not to use better names and why anyone would suggest
replacing a good name with a more generic one.

Because it means you only need to use one of them, instead of keeping
track of potentially dozens of delegate types.

Normally it's clear what you're doing from where you *use* the code.
Yes, you need to be familiar with the Action<...> and Func<...> types,
but then you can use them all over your code.

I can't say I've ever had any trouble understanding what a delegate
will be used for, based on the context.
 
J

Jon Skeet [C# MVP]

I am assuming that a similar amount of resources are used in all three
cases, just in the later the compiler handle's more of the details.

Absolutely. I wouldn't expect any difference to be significant or even
measurable. There may be no difference *at all* in release builds.
 
M

Marc Gravell

make as many delegates as you need so that
delegate names make sense
Additional to Jon's reply...

If I see a delegate argument JoesCustomWossit, then if I'm not
familiar I need to look up what the interface is from the metadata/
docs. However, if I see a delegate argument Func<float,float,bool>
then I know that it takes 2 floats and returns a bool. Combine that
with the argument name that hopefully indicates its purpose, and I
have everything I need to start coding.

Marc
 
J

jehugaleahsa

And when it comes naming *variables*, that's fine. By all means name
delegate *variables* according to what they do. But declaring an extra
type all the time seems pointless to me.


Because it means you only need to use one of them, instead of keeping
track of potentially dozens of delegate types.

Normally it's clear what you're doing from where you *use* the code.
Yes, you need to be familiar with the Action<...> and Func<...> types,
but then you can use them all over your code.

I can't say I've ever had any trouble understanding what a delegate
will be used for, based on the context.

The argument I am hearing is that, first, you are seeing it from the
caller's point of view, where all you need to know is what your method
need to look like. Second, using the built-in names is more likely to
ring a bell for other developers. Who wants to look up what a delegate
is?

My argument is this: if you are looking at it from the caller's point
of view, the delegate name is rarely important. Usually all you see is
the method being passed in. You still have to go look at the delegated
method or method taking the delegate to know which delegate the callee
is expecting. Only rarely do methods ask for a Delegate (like
BeginInvoke, for instance), rather than an Action<T> or Converter<I,
O>. I see methods taking Delegate as an opportunity to define a more
meaningful delegate. Why not use built-in delegates? My thoughts are
that when someone is interested in how your method is implemented,
they won't understand this as well:

public int GetTotalCustomerPurchases(List<ICustomer> customers,
Converter<ICustomer, int> cp)
{
int total = 0;
foreach (ICustomer c in customers)
{
if (c.Age > 18 && c.Age < 65)
{
total += cp(c); // I assume this is getting purchases

}
}
return total;
}

Someone might be able to figure out that this method takes a customer
and calls a delegate to get his or her purchase amount. To me, though,
I feel that the delegate could say a lot more about what the incoming
method should be doing. For instance
CustomerPurchaseExtractor<ICustomer, int>. Converter<ICustomer, int>
could mean just about anything and, yes, be used for many things. It
could be used for getting a customer's age, their credit rating, their
phone number, their SSN, etc., etc. That, to me, is all the more
reason to have different delegates for these methods. Someone could
easily pass an int GetSSN(ICustomer) to the GetTotalCustomerPurchases
method. The well-named delegate gives developers and opportunity to
check themselves. Here is an even better example:

public int GetTotalCustomerPurchases(List<ICustomer> customers,
Converter<ICustomer, int> ca, Converter<ICustomer, int> cp)
{
int total = 0;
foreach (ICustomer c in customers)
{
int age = ca(c);
if (age > 18 && age < 65)
{
total += cp(c); // I assume this is getting purchases
}
}
return total;
}

Here, the developer has to keep track of which one comes first. Pray
they have intellisense! Pray even more the creator was nice enough to
use good names! I didn't because I was feeling lazy today. Imagine if
you couldn't see inside the method (as is typical) and you had to
extend this code and the guy who wrote it got canned for bad
programming practices. You would have to go look up a call to it,
which could be hidden from you, to see how the creator called it. Oh,
it would have been nice if he would have just given those delegates
some better names!

Sure, my suggestion still doesn't protect you completely from
mistakes, but to me it makes your code more self-documenting, which is
important enough for me.
 
P

Peter Duniho

[...]
Sure, my suggestion still doesn't protect you completely from
mistakes, but to me it makes your code more self-documenting, which is
important enough for me.

Actually, both of your examples are flawed, in their execution and thus
subsequently your analysis.

The reason for using the Converter<TInput, TOutput> delegate type is that
you've got a function that converts things. It should actually _convert_
a customer to an integer. I would not expect someone to use the
Converter<TInput, TOutput> type for a situation where you're simply
returning some value based on some input. The Func<T, TResult> delegate
type would be much more appropriate, and makes it much more clear that
you're dealing with a method that takes a single parameter and returns
some new value based on, but not equivalent to, that parameter.

So yes, of course your examples are difficult to understand. But that's
because you used the wrong type. Not because you should have created a
brand new type. Using Func<T, TResult> would have been much less
misleading.

The other issue is that the delegate type should describe the _type_. The
variable should describe the _use_. If you're having trouble figuring out
the difference between a parameter named "ca" and a parameter named "cp",
it's not the fault of the type you used. It's the fault of the variable
names you chose.

You don't go around declaring new types for every different way you're
going to use an integer (I hope). Likewise, there's no reason to go
around declaring new types for every different way you're going to have a
method that takes an ICustomer as input and returns an integer as output.

I certainly agree that self-documenting code is a desirable goal. But
there's a right way and a wrong way to go about that. Your examples don't
demonstrate the right way.

Pete
 
J

Jon Skeet [C# MVP]

The argument I am hearing is that, first, you are seeing it from the
caller's point of view, where all you need to know is what your method
need to look like. Second, using the built-in names is more likely to
ring a bell for other developers. Who wants to look up what a delegate
is?

Yes, that's part of it.
My argument is this: if you are looking at it from the caller's point
of view, the delegate name is rarely important. Usually all you see is
the method being passed in. You still have to go look at the delegated
method or method taking the delegate to know which delegate the callee
is expecting. Only rarely do methods ask for a Delegate (like
BeginInvoke, for instance), rather than an Action<T> or Converter<I,
O>. I see methods taking Delegate as an opportunity to define a more
meaningful delegate. Why not use built-in delegates? My thoughts are
that when someone is interested in how your method is implemented,
they won't understand this as well:

public int GetTotalCustomerPurchases(List<ICustomer> customers,
Converter<ICustomer, int> cp)
{
int total = 0;
foreach (ICustomer c in customers)
{
if (c.Age > 18 && c.Age < 65)
{
total += cp(c); // I assume this is getting purchases

}
}
return total;
}

Someone might be able to figure out that this method takes a customer
and calls a delegate to get his or her purchase amount. To me, though,
I feel that the delegate could say a lot more about what the incoming
method should be doing.

To my mind, that should be in:

a) the XML documentation, which is totally absent here
b) the parameter name

Fixing these would make the method clear without having to introduce
extra types. It would also mean that someone reading the method
wouldn't have to also look up the delegate.

Sure, my suggestion still doesn't protect you completely from
mistakes, but to me it makes your code more self-documenting, which is
important enough for me.

Choosing appropriate parameter names does this in a simpler manner,
IMO.

If we pushed your logic further, we shouldn't use "int" in your example
either. After all, that's just a number - it doesn't indicate its use
at all. Instead, following your logic, we should define an Age type and
a CustomerPurchase type, and possibly a Total type, all of which just
encapsulate ints.

But no - you just use appropriate variable names instead. Why not apply
the same reasoning to delegates?

Using a straw man of "suppose we've got really badly chosen parameter
names" doesn't really help your case, because it's easier to make the
parameter names meaningful than it is to introduce extra types.
 

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