The delegates WaitCallback
and Action<Object>
share the same signature. Still, as the code below proves, they cannot be regarded as the same type.
static void Main(string[] args)
{
WaitCallback wcb = (o) => Console.WriteLine("Hello from wcb delegate");
ThreadPool.QueueUserWorkItem(wcb);//works
Action<object> action = (o) => Console.WriteLine("Hello from action<object> delegate");
ThreadPool.QueueUserWorkItem(action);//does not compile: Cannot convert from Action<object> to WaitCallback
Console.ReadLine();
}
I have two questions about this observation:
Why is it so that delegates with the same signature but a different name are not regarded as the same type? Could the language design team have chosen differently or would that have led to inconsistencies or other problems?
When the Action
delegates where introduced in the .NET framework 2.0, WaitCallback
already existed. I wonder if that were not the case, would there have been a justification for introducing the extra delegate type WaitCallback
in stead of using Action
?
From the type system's point of view WaitCallback
is a different type from Action<object>
and there exists no implicit conversion between them. So you cannot use an Action<object>
where a WaitCallback
is expected. Actual methods referenced and used as delegates, however, only care about compatibility of their argument list and return type, so instead of having an anonymous method you could have
private void Foo(object o) {
Console.WriteLine("Hello from actual method");
}
and the following lines would work without a problem:
WaitCallback wcb = Foo;
Action<object> action = Foo;
ThreadPool.QueueUserWorkItem(Foo);
Note that in this case the method's name is used to refer to it, which is parsed and handled completely different than passing a variable of a certain type to a method. For the latter you're entirely at the mercy of the actual types and their conversions and delegates are in no way special.
The specification also contains the following note:
Delegate types in C# are name equivalent, not structurally equivalent. Specifically, two different delegate types that have the same parameter lists and return type are considered different delegate types.
(Warning: speculation; I wasn't on the language design team) So this was a conscious choice and considering what I wrote above, it may not have been impossible to allow what you requested, but it'd be a major exception to how overload resolution works. So I guess that call was made in order to simplify the language. Furthermore, back in the C# 1 days, there probably weren't that many delegates that were actually structurally compatible.
As for your second point, they would probably have gone with Action
in that case. As an example, see the Task.Run
method, which takes an Action
instead of a custom delegate. For actions that take no or one parameter that seems a fairly obvious case not to introduce a new delegate type. However, for things like Action<string, string, int, double>
or equivalent Func
types I guess having an actual named type that can be documented will be far better than using the generic Action
or Func
types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With