C# 仿制药可以';我们不能推断第二个参数吗?

C# 仿制药可以';我们不能推断第二个参数吗?,c#,.net,templates,generics,C#,.net,Templates,Generics,我注意到C#编译器不会推断第二个泛型参数。 例如: C++模板代码:(是的,我知道模板不像泛型那样工作) 类测试{ 公众: 模板 T检验(V){ //用v做点什么 返回T(); } }; int i=0; 测试t=新测试(); 双j=t检验(i)//推断V为int 模板(和泛型)不能推断返回类型,所以在C++中,我给它第一个模板参数,第二个模板参数是从变量类型推断出来的。 现在,C#中的相同示例: 类测试{ 公共T检验(V),其中T:new(){ //用v做点什么 返回新的T(); } };

我注意到C#编译器不会推断第二个泛型参数。
例如:

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

类测试{
公众:
模板
T检验(V){
//用v做点什么
返回T();
}
};
int i=0;
测试t=新测试();
双j=t检验(i)//推断V为int

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

类测试{
公共T检验(V),其中T:new(){
//用v做点什么
返回新的T();
}
};
int i=0;
测试t=新测试();
双j=t检验(i)//使用泛型方法“Test.Test(V)”时出错需要“2”类型参数
但如果使用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.
类测试{
公共V测试(V),其中V:new(){
返回新的V();
}
};
int i=0;
测试t=新测试();
int j=t.试验(i)//OK推断V为int。
< > >强>为什么不能推断第二类(而C++模板中可以清楚地)? 我确信它是这样设计的(我怀疑.Net团队忽略了这一点),所以为什么它是这样设计的,我必须明确指定这两种类型

编辑:

从到目前为止我们在答案中的讨论来看,两种语言都支持通过模板参数的数量进行重载

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

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

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

< P> C被设计成比C++略微少的脑弯曲语言。 特别是,我认为把C泛型与C++模板进行比较是不太好的。因为它们在很多情况下都是两种非常不同的方法来完成类似的事情。C++方法在某些方面当然是灵活的,尽管它不允许(我理解)只存在二进制形式的模板,或者在执行时创建的新模板专长。基本上,C++模板方法与其他.NET如何组合在一起并不合适。 现在,关于为什么不能指定某些类型参数并允许推断其他类型参数(这是一个语言决策,而不是平台决策;我相信就.NET本身而言,这是可行的)——同样,我认为这是为了简单。在C#中,选择完全正确的方法和正确的类型参数已经非常复杂了——比大多数C#开发人员所能理解的还要复杂。它涉及:

  • 可能会考虑从目标的编译时类型向上扩展类型层次结构的方法
  • 按参数数重载
  • 按类型参数的数量重载
  • 命名参数的效果
  • 可选参数的影响
  • 泛型类型参数约束对参数类型的影响(注意,不是目标方法指定的约束)
  • 方法组到委托的转换
  • 匿名函数转换
  • 类型参数的类型推断
  • 动态类型
  • 广义协方差与逆变换
就我个人而言,我认为这已经足够让我动脑了,而不允许通过“M仍然可以是候选的,如果它的类型参数至少和指定的类型参数一样多的话”。是否还需要命名类型参数和可选类型参数?;)

我已经看了很多关于重载的内容,完全遵循规范,等等。我发现了一些地方让语言设计者摸不着头脑,并试图找出编译器应该做什么。我发现了编译器肯定会出错的地方。如果没有很好的理由,我不想在这里增加更多的复杂性

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

  • 该功能对终端开发人员的好处
  • 就理解该特性所花费的时间而言,该特性对最终开发人员的成本
  • 语言设计者在设计和详细说明它时所付出的代价
  • 编译器编写者正确实现它的成本
  • 测试团队彻底测试它的成本(与过载相关的所有其他因素一起)
  • 未来潜在功能的成本(如果这一功能使语言更加复杂,那么其他功能的“潜在可探索性”增加的复杂性就会降低)

在需要指定某些类型参数并推断其他类型参数的某些情况下,有一件事可以帮助您,那就是创建一个带有要指定参数的泛型静态类,然后在该类中创建一个带有要推断参数的泛型静态方法。例如,我有一个方法,给定一个可转换为动作(T,U,V)的方法以及一个T,将生成一个动作(U,V),该动作将使用最初指定的T以及U和V调用该委托。该方法将作为(vb语法)调用:

NewAction=ActionOf(FooType,BarType)。NewAction(MyFunctionOfBozFooBar,someBoz的地址) 编译器可以使用
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
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.
NewAction = ActionOf(Of FooType, BarType).NewAction(AddressOf MyFunctionOfBozFooBar, someBoz)