为什么编译器不能为我推断类型?(又名Smarter SmartEnumerable)

Sim*_*ver 2 c# generics

我正在使用Jon Skeet非常聪明的SmartEnumerable.如果您还没有看过,我建议您查看一下.

该类定义如下:

public class SmartEnumerable<T> : IEnumerable<SmartEnumerable<T>.Entry>
Run Code Online (Sandbox Code Playgroud)

构造函数是:

public SmartEnumerable(IEnumerable<T> enumerable)
Run Code Online (Sandbox Code Playgroud)

你用它来说:

new SmartEnumerable<Cat>(myCats);  // where myCats is IEnumerable<Cat>
Run Code Online (Sandbox Code Playgroud)

现在我真的想让编译器推断我有一系列的猫,并且能够说:

new SmartEnumerable(myCats);
Run Code Online (Sandbox Code Playgroud)

但是这给了我一个编译器错误:

无法从用法推断出方法'MiscUtil.Collections.SmartEnumerable.SmartEnumerable(System.Collections.Generic.IEnumerable)'的类型参数.尝试显式指定类型参数.

我不清楚为什么会这样.有没有办法绕过它.为什么它不能看到我正在使用IEnumerable<Cat>并从中推断出来.我可以改变任何东西,让它识别我正在使用的类型吗?

我真的想要一些方法来构建一个SmartEnumerable而不必指定类型 - 因为我主要在ASP.NET MVC中使用它来获取UI,我并不总是includes对类型有所依赖并依赖于var我的参考.我最终必须包含类型才能使用SmartEnumerable - 这会降低其优雅.

哦,我会直接通过电子邮件发送给John,但他反正可能会更快回复:-)


<font color=white>skeet skeet skeet, jon, jon, jon, jon skeet, skeet jon, skeetster, skeetmeister</font>

Jar*_*Par 6

试试这个代码

public static class SmartEnumerable {
  public static SmartEnumerable<T> Create<T>(IEnumerable<T> source) {
    return new SmartEnumerable<T>(source);
  }
}

void Example() {
  IEnumerable<string> myCats = GetMyCats();
  var se = SmartEnumerable.Create(myCats);
}
Run Code Online (Sandbox Code Playgroud)

您的代码失败,因为C#无法在构造函数上推断泛型参数.但是C#能够推断其他方法的泛型参数.

在C#中,拥有一个只有通用参数才能区分名称的类是完全合法的.例如Foo和Foo <T>(在引擎盖下它们实际上是不同的名字).因此,上述示例适用于大多数情况.每当我定义一个泛型类时,我个人都会使用它,其中构造函数需要足够的参数来推断完整类型.


Bry*_*tts 5

我同意JaredPar.我想指出你也可以做一个扩展方法:

public static SmartEnumerable<T> AsSmart<T>(this IEnumerable<T> source)
{
    return new SmartEnumerable<T>(source);
}
Run Code Online (Sandbox Code Playgroud)

你会像这样使用它:

var smartEnumerable = myCats.AsSmart();
Run Code Online (Sandbox Code Playgroud)

(这个例子听起来很有趣)

编辑:

Per Jon Skeet,我改名ToSmartAsSmart.