generics不能推断第二个参数?

我注意到C#编译器没有推断出第二个generics参数。
例:

C ++模板代码:(我知道模板不像generics那样工作)

class Test { public: template  T test(V v) { //do something with v return T(); } }; int i = 0; Test t = new Test(); double j = t.test(i); //infers V as int 

模板(和generics)不能推断返回类型,所以在C ++中我给它第一个模板参数,第二个模板参数是从变量类型推断出来的。

现在,在C#中使用相同的示例:

 class Test { public T test(V v) where T: new() { //do something with v return new T(); } }; int i = 0; Test t = new Test(); double j = t.test(i); //Error Using the generic method 'Test.test(V)' requires '2' type arguments 

但如果我使用1种类型,我不必明确指定类型:

 class Test { public V test(V v) where V: new() { return new V(); } }; int i = 0; Test t = new Test(); int j = t.test(i); //OK infers V as int. 

那么, 为什么 C#generics不能推断第二种类型(而在c ++模板中它显然可以)?
我确信它是这样设计的(我怀疑.Net团队忽略了这一点),那么为什么我必须这样设计我必须明确指定这两种类型?

编辑:

根据我们目前在答案中的讨论,两种语言都支持按模板参数的数量进行重载。

那么, 为什么 C#这样设计呢? 语言实现中有什么不同,不允许只显式声明一个参数?

C#被设计成比C ++略逊一筹的语言。

特别是,我认为将C#generics与C ++模板进行比较出于各种原因并不是一个好主意 – 从根本上说,它们在某些情况下完成两种截然不同的方法来完成类似的事情。 C ++方法在某些方面肯定是灵活的 – 虽然它不允许(据我所知)模板只存在于二进制forms,或者在执行时创建新的模板特化。 基本上,C ++模板方法与.NET结合在一起的其余部分并不相符。

现在为什么你不能指定一些类型参数并允许推断其他参数(这是一个语言决策而不是平台决策;我相信就.NET本身而言,这是可行的) – 再次,我相信这是为了简单起见。 选择正确的方法正确的类型参数在C#中已经非常复杂了 – 比大多数C#开发人员更加复杂。 它涉及:

  • 从目标的编译时类型中潜在地考虑类型层次结构的方法
  • 按参数数量重载
  • 类型参数的数量重载
  • 命名参数的效果
  • 可选参数的效果
  • generics类型参数约束对参数类型的影响( 不是目标方法指定的约束,注意)
  • 用于委派转化的方法组
  • 匿名函数转换
  • 键入类型参数的推断
  • 动态打字
  • 通用协方差和逆变

就个人而言,我认为这足以引起我的注意,而不允许更多的可能性“如果M 至少具有与指定类型参数一样多的类型参数,那么它仍然可以成为候选者”。 您还想要命名类型参数和可选类型参数吗? ;)

我已经看了很多重载,完全遵循规范等等。我发现了让语言设计师抓住头脑并尝试弄清楚编译器应该做什么的区域。 我找到了编译器肯定出错的区域。 如果没有一个很好的理由,我不想在这里增加任何复杂性。

所以,是的,它基本上是为了简单起见,有时这很痛苦 – 但通常你可以解决它。 对于每个潜在的function,您需要考虑:

  • 该function对终端开发人员的好处
  • 在理解它的时间方面,最终开发人员的function成本
  • 语言设计者在设计和完整指定时所付出的代价
  • 编译器编写者正确实现它的成本
  • 测试团队彻底测试它的成本(与重载的其他一切相关)
  • 未来潜在function的成本(如果这使得语言更复杂,为其他function留下更少“潜在可修复”的额外复杂性)

正如Dan所说,C#不允许您仅推断通用参数集的某些类型参数。 这可能会根据通用参数的数量启用重载(C#允许,至少对于generics类)。

但是,您可以指定generics类的参数,并推断该类中generics方法的参数。 但这种解决方法并不总是一个好的解决方案。

在某些情况下,有人希望指定某些类型参数并推断其他参数,有一点可以帮助创建一个包含想要指定的参数的通用静态类,然后在该类中有一个带参数的通用静态方法想要推断。 例如,我有一个方法,给定一个可转换为Action(T,U,V)的方法,以及一个T,将生成一个Action(U,V),它将使用最初指定的方式调用该委托T与U和V一起使用。该方法将被调用为(vb语法):

   NewAction = ActionOf(Of FooType,BarType).NewAction(AddressOf MyFunctionOfBozFooBar,someBoz)

编译器可以使用someBoz的类型确定其中一个generics类型参数,即使它需要明确指定FooType和BarType参数。