Reading through chapter 2 (see, I’m being good) a new thought about return type covariance occurred to me. This is odd in itself, because I thought I’d exhausted my own supply of ideas around variance (which isn’t the same as knowing everything about it, of course – it just means I don’t expect to have anything new to say).
Just as a reminder, in C# 1 delegates were completely invariant – in order to create a delegate instance from a method group, for instance, the signature had to match exactly. For instance, suppose we had a delegate type declared as:
We couldn’t (in C# 1) use the following method to create an instance of ObjectFactory
:
{
return new StringBuilder();
}
Even though a StringBuilder
is always an object
, the signatures don’t match exactly, and it was prohibited.
C# 2 allows this, however, so it’s legal to write:
So far, so good. (Yes, a generic delegate type would be nicer, but I’m avoiding the variance issues with generics for this post. Let’s not make things more complicated than they need to be.) Just to be absolutely clear about this, it’s valid and legal because there’s nothing you can do with factory
now which will break normal type safety. You can call factory()
and be absolutely sure that it will return an object
of some kind (or null
) so it’s as safe as anything else.
Now, what about a delegate type which has a void return type:
You can’t use CreateStringBuilder
as the target of an instance of Action
– C# 2 and even C# 3 completely disallow it. My guess is that the CLR disallows it internally. Why is this? Again, any use of an Action
delegate can’t possibly care about what the target returns, because it’s not declared to return anything.
I strongly suspect that the answer lies in the implementation of the CLR rather than in any deep semantic reason – the CLR probably needs to know whether or not there’s going to be a return value, in order to do appropriate things with the stack. Even so, it seems a bit of a pity, in terms of elegance. I can’t say I’ve ever felt the need for this in real life, and it would be reasonably easy to fake (for up to four parameters) in .NET 3.5 just by writing a converter from Func<X> to Action<X>, Func<X,Y> to Action<X,Y> etc. It niggles a bit though :)
ObjectFactory factory – i’m not sure it’s corrent
LikeLike
Blost: What exactly do you mean? It certainly compiles. Here’s a complete program:
using System;
using System.Text;
delegate object ObjectFactory();
class Test
{
public StringBuilder CreateStringBuilder()
{
return new StringBuilder();
}
public void Foo()
{
ObjectFactory factory = CreateStringBuilder;
}
static void Main(){}
}
That builds with C# 2.
Jon
LikeLike