Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot find definition though intellisense lists it?

I'm getting a strange error with Visual Studio 10 (and now 11 as well). I have an extension method

public static S Foo<S, T>(this S s) where S : IEnumerable<T>
{
    return s;
}

Now if I call

"".Foo(); // => 'string' does not contain a definition for 'Foo' and no extension method 'Foo' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)

I'm not at all understanding what's happening under hood. The annoying part is that the intellisense lists Foo for IEnumberable<T>s. At best it should have given a type can't be inferred error.

If I call it this way:

Extension.Foo(""); // => The type arguments for method 'Extension.Foo<S,T>(S)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Why cannot type be inferred in the above case?

More:

Suppose I have:

public static S Foo<S, T>(this S s, T t) where S : IEnumerable<T>
{
    return s;
}

And if I call:

"".Foo(1);

The type inference is so smart here to tell me that Foo should be returning IEnumerable<int> and string is not all that!!

So if compiler can know Foo is expecting a char as the first argument, then why doesn't my first example just compile? In other words why is that in the first example the compiler know T in that case is char?

As expectedly this works for the second example:

"".Foo('l');

I'm just wondering why can't T be inferred as char in first example, after all string is IEnumberable<char>.


Edit:

I got the answer from SLaks. But it's so strange that C# doesn't do this (kind of type inference) considering compiler takes into account the generic constraints as well when exposing the available methods to operate on an object.

In other words:

public static S Foo<S, T>(this S s)
{
    return s;
}

makes Foo available on all objects.

public static S Foo<S, T>(this S s) where S : IEnumerable<T>
{
    return s;
}

makes Foo available on all IEnumerable<T>s since it knows S is IEnumerable<T>. So I was thinking C# will be even inferring the type of T! Thanks everyone! ;)

like image 724
nawfal Avatar asked Nov 13 '12 14:11

nawfal


1 Answers

The type inference engine isn't smart enough to do that.

C# type inference only looks at the method signature.
Generic constraints are not part of the signature.

Since T is not used directly in the signature, the compiler will not infer it.

like image 189
SLaks Avatar answered Sep 30 '22 04:09

SLaks