【发布时间】:2016-11-15 21:51:45
【问题描述】:
在这个问题中,当提到编译器时,我实际上指的是 Roslyn 编译器。使用 IntelliSense 时出现问题,推测是同一个编译器。
出于演示目的和完整性,使用了以下类(使用带有 C# 6.0 和 .NET 4.6.1 的 Visual Studio 2015):
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> { }
看下面的扩展方法:
public static void FooBar<T1, T2>(
this Helper<IEnumerable<T1>> helper,
Expression<Func<T1, IEnumerable<T2>>> expression) { ... }
编译器能够在这样消费时推断它:
Helper<IEnumerable<B>> helper = ...;
helper.FooBar(l => l.C); //T1 is B and T2 is C
还请看这个重载的扩展方法:
public static void FooBar<T1, T2, T3>(
this Helper<T1> helper,
Expression<Func<T1, IEnumerable<T2>>> expression1,
Expression<Func<T2, IEnumerable<T3>>> expression2) { ... }
当这样输入T1时,编译器不能推断:
Helper<A> helper = ...;
helper.FooBar(l => l. //compiler/IntelliSense cannot infer that T1 is A
当我将鼠标悬停在扩展方法上时,我也会收到此错误消息(我已将 < 和 > 字符分别替换为 [ 和 ],因为 StackOverflow 不能格式化那些引用):
无法推断方法 'FooBar[T1,T2](this Helper[IEnumerable[T1]], Expression[Func[T1, IEnumerable[T2]]])' 的类型参数 从用法上。尝试明确指定类型参数。
但是当像这样手动完成它时:
helper.FooBar(l => l.B, l => l.C); //compiler infers that T1 is A, T2 is B and T3 is C
编译器很高兴。
为什么编译器/IntelliSense(或 Visual Studio 的自动完成功能)无法识别 T1 并希望我在开始输入时明确指定类型参数?
请注意,如果我在示例中的所有位置都省略了 IEnumerable<>,编译器可以在键入时愉快地推断出所有内容。
手动输入l => l.B 后,编译器也很高兴。然后它知道T1 是A,因此您可以在IntelliSense 的帮助下表达最后一个参数。
【问题讨论】:
-
当您说“编译器无法推断 T1 是 A”时,您实际上是指 IDE 的自动完成功能,对吧?
-
整个 Roslyn 项目背后的想法之一是拥有一个既能编译代码又能在 IntelliSense 中运行的单一编译器。然而,在某些方面,IntelliSense 与编译东西有点不同(我认为需要更多信息)。所以我们仍然有一些情况下 IntelliSense 只是保释我们,而代码仍然可以愉快地编译:-(
-
我更想说这是“设计”的限制:)
-
@StefanSteinegger 我希望专家确认这是否是一个合法的错误,或者这是一个有意设计受限的功能。
标签: c# .net generics visual-studio-2015 roslyn