Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't these generic types be inferred?

I have the following code:

public static class CardView {
    public static object Column<TModel, TResult>(Func<TModel, TResult> field) {
        return null;
    }
}

public class Person 
{
    public string Name { get; set; }
    public bool Gender { get; set; }
}

void Main()
{
    var model = new Person() { Name = "Andre", Gender = true };

    var b = CardView.Column(model => model.Name); // ERROR
    // The type arguments for method 'UserQuery.CardView.Column<TModel,TResult>(System.Func<TModel,TResult>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
}

For some reason it's not able to infer the generic types for the Column method. I need to know why. I can't give up the type inference and specify the types myself because it's just a case study for a large problem where it will be indispensable.

EDIT

I misspelled the code =/ just fixed it

like image 257
André Pena Avatar asked Dec 07 '11 15:12

André Pena


2 Answers

In order for the compiler to perform type inference it has to be given some sort of type information. In this scenario the only information it's provided is an untyped lambda expression. The compiler really has nothing to go on here.

There are a couple of ways to resolve this. The easiest is to add a type to the lambda paramater

var b = CardView.Column((Person m) => m.Name);
like image 58
JaredPar Avatar answered Sep 20 '22 02:09

JaredPar


The technical answer would be "because the specification doesn't say you can do that". Quoting the spec, section 7.5.2 (type inference):

7.5.2.1 The first phase

For each of the method arguments Ei:

  1. If Ei is an anonymous function, an explicit parameter type inference (§7.5.2.7) is made from Ei to Ti
  2. Otherwise, if Ei has a type U and xi is a value parameter then a lower-bound inference is made from U to Ti.
  3. Otherwise, if Ei has a type U and xi is a ref or out parameter then an exact inference is made from U to Ti.
  4. Otherwise, no inference is made for this argument.

and:

7.5.2.7 Explicit parameter type inferences

An explicit parameter type inference is made from an expression E to a type T in the following way:

  • If E is an explicitly typed anonymous function with parameter types U1…Uk and T is a delegate type or expression tree type with parameter types V1…Vk then for each Ui an exact inference (§7.5.2.8) is made from Ui to the corresponding Vi.

Since the anonymous function in your example is not explicitly typed, no inference can be made. This also tells us that to have the inference made, you can help by specifying the type of the function:

var b = CardView.Column((Person m) => m.Name); 

Now this is explicitly a Func<Person, string>, so inference is successful.

like image 23
Jon Avatar answered Sep 20 '22 02:09

Jon