收录日期:2019/06/20 01:21:12 时间:2010-05-04 13:42:53 标签:c#,.net,generics,type-inference

Why does this work? I'm not complaining, just want to know.

void Test()
{    
    int a = 1;
    int b = 2;

    What<int>(a, b);
    // Why does this next line work?
    What(a, b);
}

void What<T>(T a, T b)
{

}

It works because a and b are integers, so the compiler can infer the generic type argument for What.

In C# 3, the compiler can also infer the type argument even when the types don't match, as long as a widening conversion makes sense. For instance, if c were a long, then What(a, c) would be interpreted as What<long>.

Note that if, say, c were a string, it wouldn't work.

The C# compiler supports type inference for generics, and also commonly seen if you are using the var keyword.

Here int is inferred from the context (a and b) and so <int> is not needed. It keeps code cleaner and easier to read at times.

Sometimes your code may be more clear to read if you let the compiler infer the type, sometimes it may be more clear if you explicitly specify the type. It is a judgement call on your given situation.

It's using type inference for generic methods. Note that this has changed between C# 2 and 3. For example, this wouldn't have worked in C# 2:

What("hello", new object());

... whereas it would in C# 3 (or 4). In C# 2, the type inference was performed on a per-argument basis, and the results had to match exactly. In C# 3, each argument contributes information which is then put together to infer the type arguments. C# 3 also supports multi-phase type inference where the compiler can work out one type argument, then see if it's got any more information on the rest (e.g. due to lambda expressions with implicit parameter types). Basically it keeps going until it can't get any more information, or it finishes - or it sees contradictory information. The type inference in C# isn't as powerful as the Hindley-Milner algorithm, but it works better in other ways (in particular it always makes forward progress).

See section 7.4.2 of the C# 3 spec for more information.

The compiler infers the generic type parameter from the types of the actual parameters that you passed.

This feature makes LINQ calls much simpler. (You don't need to write numbers.Select<int, string>(i => i.ToString()), because the compiler infers the int from numbers and the string from ToString)

The compiler can infer type T to be an int since both parameters passed into What() are of type int. You'll notice a lot of the Linq extensions are defined with generics (as IEnumerable) but are typically used in the manner you show.

If the subject of how this works in C# 3.0 is interesting to you, here's a little video of me explaining it from back in 2006, when we were first designing the version of the feature for C# 3.0.

http://blogs.msdn.com/ericlippert/archive/2006/11/17/a-face-made-for-email-part-three.aspx

See also the "type inference" section of my blog:

http://blogs.msdn.com/ericlippert/archive/tags/Type+Inference/default.aspx

The compiler is smart enough to figure out that the generic type is 'int'