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.