In this question, when mentioning the compiler, I'm actually referring to the Roslyn compiler. The problem arises when using IntelliSense, which is presumed to be the same compiler.
For demonstration purposes and completeness, the following classes are used (using Visual Studio 2015 with C# 6.0 and .NET 4.6.1):
public class A
{
public IEnumerable<B> B { get; set; }
}
public class B
{
public IEnumerable<C> C { get; set; }
}
public class C { }
public class Helper<T> { }
Behold the following extension method:
public static void FooBar<T1, T2>(
this Helper<IEnumerable<T1>> helper,
Expression<Func<T1, IEnumerable<T2>>> expression) { ... }
The compiler is able to infer it while consuming like this:
Helper<IEnumerable<B>> helper = ...;
helper.FooBar(l => l.C); //T1 is B and T2 is C
Also behold this overloaded extension method:
public static void FooBar<T1, T2, T3>(
this Helper<T1> helper,
Expression<Func<T1, IEnumerable<T2>>> expression1,
Expression<Func<T2, IEnumerable<T3>>> expression2) { ... }
The compiler is NOT able to infer T1
when typing it like this:
Helper<A> helper = ...;
helper.FooBar(l => l. //compiler/IntelliSense cannot infer that T1 is A
This screenshot example will describe more of what I mean with not able to infer:
Also I'm getting this error message when hovering over the extension method with my mouse (I've replaced the <
and >
characters with [
and ]
respectively, because StackOverflow cannot format those in a quote):
The type arguments for method 'FooBar[T1,T2](this Helper[IEnumerable[T1]], Expression[Func[T1, IEnumerable[T2]]])' cannot be inferred from the usage. Try specifying the type arguments explicitly.
But when completing it manually like this:
helper.FooBar(l => l.B, l => l.C); //compiler infers that T1 is A, T2 is B and T3 is C
the compiler is happy.
Why can't the compiler/IntelliSense (or the autocomplete feature of Visual Studio) figure out T1
and wants me to specify the type arguments explicitly when I start typing?
Note that if I omit IEnumerable<>
everywhere in my examples, the compiler can happily infer everything while typing.
The compiler is also happy after you manually type in l => l.B
. It then knows T1
is A
, so you can express the last argument with the help of IntelliSense.
If I understood you correctly, everything is working as expected for me in VS2013:
Your first case:
Your second case:
I'm starting to type the l.
and IntelliSense shows me that l
has a property B
that can be used. So if I'm right and it infers correctly in VS2013 whereas it doesn't infer in VS2015, then it's definitely a bug in VS2015 IntelliSense that can be reported to Microsoft.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With