Can't assign methods that return value types to Func<dynamic> [duplicate]
Asked Answered
H

1

8

I have a variable of type Func<dynamic> and I am trying to assign it a value. If I assign it to a method that returns a value type (e.g. int), I get the error

'int MethodName()' has the wrong return type

If I wrap the method in a lambda call, however, it works fine. Also methods that return reference types seem to work fine.

private string Test()
{
    return "";
}

private int Test2()
{
    return 0;
}

Func<dynamic> f = Test;           // Works
Func<dynamic> g = Test2;          // Does not
Func<dynamic> h = () => Test2();  // Works

What's wrong with the direct assignment case?

Homage answered 5/11, 2015 at 19:29 Comment(2)
It's not just dynamic. If you change your Func<dynamic> to Func<object> you get the same error, and I think it's because boxing operation would get introduced indirectly, and compiler is not ok with that, but I can't find anything in the spec that would describe that situation.Wealth
@Wealth From the specs on delegate compatability, "For each value parameter (a parameter with no ref or out modifier), an identity conversion (§6.1.1) or implicit reference conversion (§6.1.6) exists from the parameter type in D to the corresponding parameter type in M." There is an implicit conversion in this case, but it's not an identity or reference conversion.Ectomorph
I
4

This has nothing to do with dynamic or delegate TResult Func<out TResult>(). You will see the same behavior in this code:

interface I<out T> { }
class C<T> : I<T> { }
...
I<int> a = new C<int>();
I<string> b = new C<string>();
I<object> x = a; // compiler error
I<object> y = b; // no compiler error

For some reason, value types like int will automatically cast to object or dynamic, but I<int> will not automatically cast to I<object> or I<dynamic>. I can't find where in the language reference this is specified.

The reason Func<dynamic> h = () => Test2(); works in your code is because it only requires int to cast to dynamic implicitly, which is fine. It does not require Func<int> to cast to Func<dynamic> implicitly.

Intergrade answered 5/11, 2015 at 19:47 Comment(1)
Full explanation by Eric Lippert: https://mcmap.net/q/145361/-why-doesn-39-t-delegate-contravariance-work-with-value-typesIntergrade

© 2022 - 2024 — McMap. All rights reserved.