C#类型推断:在不应该的地方失败';T

C#类型推断:在不应该的地方失败';T,c#,.net,generics,type-inference,C#,.net,Generics,Type Inference,请注意下面的代码。冒犯的台词已被注释掉 interface I<R> { } class C : I<int> { } class Program { private static void function<T, R>(T t) where T : class, I<R> { } static void Main(string[] args) { // function(new C()

请注意下面的代码。冒犯的台词已被注释掉

interface I<R> { }

class C : I<int> { }

class Program
{
    private static void function<T, R>(T t) where T : class, I<R>
    {
    }

    static void Main(string[] args)
    {
        // function(new C()); // wont compile
        function<C, int>(new C());
    }
}
接口I{}
C类:I{}
班级计划
{
私有静态空洞函数(T),其中T:class,I
{
}
静态void Main(字符串[]参数)
{
//函数(新C());//无法编译
函数(新C());
}
}
我认为类型推断应该找出类型,因为参数
T
提供了第一种类型,而
I
提供了第二种类型


是否有办法重新设计函数,以便调用方不必指定类型?

如果要保留所有约束,则不需要。但是,这应该同样适用,除非您有特定的理由禁止值类型:

private static void function<R>(I<R> t)
private静态无效函数(it)
不,C#不支持这种推断

直接使用接口并使用get type.查找类型

private static void function<R>(I<R> t)
{
   Type typeofT = typeof(T);
}
private静态无效函数(it)
{
typeofT=typeof(T);
}
再好不过了


如果需要使用T调用另一个泛型方法,可以使用typeofT-Type通过反射构建泛型调用。

有多种方法可以向类型推断添加额外的规则-人类可以应用但编译器(遵守语言规范)不能应用的逻辑位

但是,在您建议确实应该更新该语言以使类型推断工作更灵活之前,我强烈建议您阅读现有规范。如果您能够足够容易地理解这一点,您仍然认为值得将其变得更复杂,在上发布功能请求-但我个人认为这已经够复杂了。我想说,这比C#2.0要好得多

然而,为了提出相反的观点,有几种语言(特别是函数式语言)具有更强大的类型推理机制。这里总是有优点和缺点-我相信C#中当前推理系统的优点之一是它总是取得进展或停止,例如-关于这一点和其他一些类型的推理问题有更多的信息。

class D:I,I{}
class D : I<int>, I<string> { }
//
function<D, int>(new D());
function<D, string>(new D());
//is R int or string?
function(new D());  
// 函数(新D()); 函数(新D()); //R是int还是string? 函数(新D());
C#不支持这种类型推断。考虑这种情况,这给问题增加了一点模糊性。
class Other : I<int>, I<Student>{ ... }
void Example(){
  function(new D());
}
class-Other:I,I{…}
void示例(){
函数(新D());
}
在这种情况下,应该选择哪一个我是模棱两可的


如果你期待C#4.0,那么问题只会随着他们添加的新变化特性而增加。

是的,但规范可能有一个特殊情况,即C只实现I。这一切都是可行的,但它会使语言更加复杂。当然,如果我稍后修改C以添加I,那么我将打破这个推论。。。中断将远离源的更改。。。糟糕的情况。在这种情况下,它可能会报告一个歧义(您应该添加一个用于消除歧义的转换),但只接受一个大小写。如果您转换为I,您将不符合类限制。我认为如果它是歧义的,它应该报告一个歧义,但在其他情况下使用它可以处理的信息。歧义的解决方法是指定类型(如David B的代码段)。我不相信这种“远离源代码”的问题——所有支持任何类型重用的编程语言都能够让您在一个位置进行更改,从而在一千个其他位置中断代码。您是指t.GetType()?T在您修改的方法中不再是类型参数。