泛型不能推断第二个参数?

Yoc*_*mer 19 .net c# generics templates

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

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

class Test {
public:
template <class T,class V> 
    T test(V v) {
       //do something with v
       return T();
    }
};

int i = 0;
Test t = new Test();
double j = t.test<double>(i); //infers V as int
Run Code Online (Sandbox Code Playgroud)

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

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

class Test {
    public T test<T,V>(V v) where T: new() {
       //do something with v
       return new T();
    }
};

int i = 0;
Test t = new Test();
double j = t.test<double>(i); //Error Using the generic method 'Test.test<T,V>(V)' requires '2' type arguments
Run Code Online (Sandbox Code Playgroud)

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

class Test {
    public V test<V>(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.
Run Code Online (Sandbox Code Playgroud)

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

编辑:

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

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

Jon*_*eet 30

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

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

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

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

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

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

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

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

  • 只是一个逗号会很有用,比如 `call&lt;MyClass, &gt;` ... 不是很美观,但在指定通用参数 (?) 类型时已经存在于语法中 (2认同)

Ben*_*igt 8

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

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