Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type arguments cannot be inferred when passing method as argument [duplicate]

Tags:

c#

Given this code:

class C
{
    C()
    {
        Test<string>(A); // fine
        Test((string a) => {}); // fine
        Test((Action<string>)A); // fine

        Test(A); // type arguments cannot be inferred from usage!
    }

    static void Test<T>(Action<T> a) { }

    void A(string _) { }
}

The compiler complains that Test(A) can't figure out T to be string.

This seems like a pretty easy case to me, and I swear I've relied far more complicated inference in other generic utility and extension functions I've written. What am I missing here?

Update 1: This is in the C# 4.0 compiler. I discovered the issue in VS2010 and the above sample is from a simplest-case repro I made in LINQPad 4.

Update 2: Added some more examples to the list of what works.

like image 282
scobi Avatar asked Nov 17 '22 00:11

scobi


2 Answers

Test(A);

This fails because the only applicable method (Test<T>(Action<T>)) requires type inference, and the type inference algorithm requires that each each argument be of some type or be an anonymous function. (This fact is inferred from the specification of the type inference algorithm (§7.5.2)) The method group A is not of any type (even though it is convertable to an appropriate delegate type), and it is not an anonymous function.

Test<string>(A);

This succeeds, the difference being that type inference is not necessary to bind Test, and method group A is convertable to the required delegate parameter type void Action<string>(string).

Test((string a) => {});

This succeeds, the difference being that the type inference algorithm makes provision for anonymous functions in the first phase (§7.5.2.1). The parameter and return types of the anonymous function are known, so an explicit parameter type inference can be made, and a correspondense is thereby made between the types in the anonymous function (void ?(string)) and the type parameter in the delegate type of the Test method’s parameter (void Action<T>(T)). No algorithm is specified for method groups that would correspond to this algorithm for anonymous functions.

Test((Action<string>)A);

This succeeds, the difference being that the untyped method group parameter A is cast to a type, thereby allowing the type inference of Test to proceed normally with an expression of a particular type as the only argument to the method.

I can think of no reason in theory why overload resolution could not be attempted on the method group A. Then—if a single best binding is found—the method group could be given the same treatment as an anonymous function. This is especially true in cases like this where the method group contains exactly one candidate and it has no type parameters. But the reason it does not work in C#4 appears to be the fact that this feature was not designed and implemented. Given the complexity of this feature, the narowness of its application, and the existance of three easy work-arounds, I am not going to be holding my breath for it!

like image 185
Jeffrey L Whitledge Avatar answered Dec 21 '22 11:12

Jeffrey L Whitledge


I think it's because it's a two-step inference:

  • It has to infer that you want to convert A to a generic delegate

  • It has to infer what the type of the delegate parameter should be

I'm not sure if this is the reason, but my hunch is that a two-step inference isn't necessarily easy for the compiler.


Edit:

Just a hunch, but something is telling me the first step is the problem. The compiler has to figure out to convert to a delegate with a different number of generic parameters, and so it can't infer the types of the parameters.

like image 30
user541686 Avatar answered Dec 21 '22 10:12

user541686