Given the following class:
public class MyType
{
public static implicit operator MyType(Func<MyType> wrapper) {
return wrapper();
}
}
From the implicit cast of Func<MyType>
to MyType
, I assumed the following would be possible:
public MyType MyTypeWrapper() {
return new MyType();
}
public void MyTestMethod() {
MyType m = MyTypeWrapper; // not a call!
}
However I'm getting:
Cannot convert method group 'MyTypeWrapper' to non-delegate type 'Test.MyType'. Did you intend to invoke the method?
Which, unfortunately for me, when searched for (as I half expected) resulted in tons of questions to which the answer was:
Hey, ya dun goofed; toss
()
on the end ofWhateverMethod
!
Now, as I'm typing this, I've noticed that an explicit cast does in fact compile:
MyType m = (MyType) MyTypeWrapper;
Why is it that I cannot implicitly cast a Func<MyType>
to MyType
as I've described?
This is unfortunate. I'm pretty sure you've found a compiler bug, and this section of the specification is extremely difficult to read.
Section 6.4.4 of the C# 4 specification explains why your implicit conversion is illegal.
The algorithm goes like this. First look at the source type and target type. There is no source type because a method group has no type. The target type is MyType
. So search MyType
for user-defined implicit conversions. Now the question is: what is the set of applicable user-defined operators ... that convert from a type encompassing S? S
is the source type and we have already established that there is no source type. So this is already evidence that the conversion should fail. But even if the compiler for some reason decides that your Func<MyType>
conversion is applicable, the rule is a standard implicit conversion ... is performed. Method group conversions are deliberately not classified as standard conversions.
So that's why it should be illegal.
Why then is the explicit cast legal?
There's no justification for that. This appears to be a bug.
This is unfortunate; many apologies for the error. I shall report it to my former colleagues; if they have an analysis which conflicts with mine, I'll update the answer.
UPDATE: My former colleagues inform me that the spec problem whereby the source expression is assumed to have a type will be addressed by a rewording in the next release of the spec. No word yet as to whether the explicit cast behavior is a bug.
You're already using the built-in implicit conversion from method group to Func<MyType>
.
The compiler won't do two implicit conversions at once.
Once you have an explicit cast to your class, the compiler knows to look for an implicit cast to any type that can be explicitly casted to your class.
Because the C# compiler isn't able to convert MyTypeWrapper
into a Func<MyType>(MyTypeWrapper)
. There's a difference between a method group and an actual delegate.
This compiles and runs fine:
MyType m = new Func<MyType>(MyTypeWrapper);
There is an implicit conversion from a method group to a delegate type that matches that group, and there is your user defined implicit conversion from that delegate to a type. The general idea here is that the compiler is only going to use one implicit conversion in a row at a time. When it has an A and needs a C it looks for conversions from A to C, not from A to any type B and from that type to C. That algorithm goes from O(n) to O(n^2) (not to mention possibly being quite confusing for programmers).
The reason your code works when using an explicit cast to MyType
is that you're no longer chaining implicit conversions.
The signature of MyTestMethod
MATCHES the signature of Func<MyType>
but is NOT a Func<MyType>
. Func has defined some implicit casts itself to allow you to assign such methods as Funcs, but you must explicitly cast for the signature to apply, because the compiler will not chain implicit casts together for you:
MyType m = (Func<MyType>)MyTypeWrapper; // not a call!
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