究竟谁最后决定什么是通用类型?

Roy*_*mir 7 c# generics .net-4.0

我有这个功能

 public static T2 MyFunc<T1, T2>( T1 a, T1 b, T2 c)
        {
            return c;
        }     
Run Code Online (Sandbox Code Playgroud)

我正在创建2个Persons类实例:

 class Person
         {  }

            Person p = new Person();
            Person p2 = new Person();
Run Code Online (Sandbox Code Playgroud)

我正在调用函数:

 MyClass.MyFunc(p, p2, 5);
Run Code Online (Sandbox Code Playgroud)

我的问题是:

谁真正决定T1类型?(p?p2?)

因为如果左边是Apple,那么他会检查第二个是Apple也是苹果

如果第二个是橙色 - 他应该检查第一个是橙色.

在此输入图像描述

在编译时问它是否会失败如果不一样,这似乎很奇怪.

仍然 - 谁决定类型?

第二 - 如果我将其更改为动态 - 在运行时 - 谁将决定T1类型应该是什么?

Eri*_*ert 13

在高级别,方法类型推断的工作方式如下.

首先,我们列出所有参数 - 您提供的表达式 - 以及它们相应的形式参数类型.

让我们看一个比你给出的更有趣的例子.假设我们有

class Person {}
class Employee : Person {}
...
Person p = whatever;
Employee p2 = whatever;
Run Code Online (Sandbox Code Playgroud)

和同一个电话.所以我们做了对应:

p  --> T1
p2 --> T1
5  --> T2
Run Code Online (Sandbox Code Playgroud)

然后我们列出每个类型参数的"边界"以及它们是否"固定".我们有两个类型参数,我们从没有上限,下限或精确边界开始.

T1: (unfixed) upper { }  lower { }  exact { }
T2: (unfixed) upper { }  lower { }  exact { }
Run Code Online (Sandbox Code Playgroud)

(回想一下我们最近讨论关于类型的相对大小另一个问题是基于一个类型是否或多或少的限制;一类是比较严格的是更小的,比一个限制较少长颈鹿比动物更小,因为更多事物是动物而不是长颈鹿."上"和"下"约束集正是这样:给定类型参数的类型推断问题的解决方案必须大于或等于每个下限,小于或等于每个上限,每个精确界限相同.)

然后我们查看每个参数及其相应的类型.(如果参数是lambdas,那么我们可能必须弄清楚我们查看参数的顺序,但是你没有任何lambdas,所以让我们忽略那个细节.)对于每个参数,我们对形式参数类型进行推断,并将我们推导出的关于该推断的事实添加到绑定集.因此,在查看第一个参数后,我们推导出边界:

T1: (unfixed) upper { }  lower { Person }  exact { }
T2: (unfixed) upper { }  lower { }  exact { }
Run Code Online (Sandbox Code Playgroud)

在第二个参数之后,我们推导出界限

T1: (unfixed) upper { }  lower { Person, Employee }  exact { }
T2: (unfixed) upper { }  lower { }  exact { }
Run Code Online (Sandbox Code Playgroud)

在第三个参数之后我们推导出界限:

T1: (unfixed) upper { }  lower { Person, Employee }  exact { }
T2: (unfixed) upper { }  lower { int }  exact { }
Run Code Online (Sandbox Code Playgroud)

在我们尽可能多地取得进展之后,我们通过在满足每个边界的边界集中找到最佳类型来 "修复"边界.

对于T1,边界集中有两种类型,PersonEmployee.是否有其中一个满足边界集中的每个边界?是.Employee不满足Person约束,因为Employee比较小的类型Person; Person是一个下限 - 它意味着没有比Person合法更小的类型.Person确实满足所有边界:Person与...相同Person且大于Employee,因此它满足两个边界.满足每个边界的边界集中的最佳类型是T1 Person和T2显然是int因为在T2的边界集中只有一种类型.然后我们修复类型参数:

T1: (fixed) Person
T2: (fixed) int
Run Code Online (Sandbox Code Playgroud)

然后我们问"我们对每个类型参数都有一个固定的界限吗?" 答案是"是",因此类型推断成功.

如果我改变第一个参数的类型,dynamic那么T1如何推断?

如果任何参数是动态的,那么T1和T2的推断将推迟到运行时,此时语义分析器将该值的最可导出的可访问运行时类型视为动态参数提供的下限的类型.


如果您对这个主题感兴趣并想要了解更多内容,那么我可以在此视频中解释C#3版本的算法:

http://blogs.msdn.com/b/ericlippert/archive/2006/11/17/a-face-made-for-email-part-three.aspx

(C#3没有上限,只有较低和精确的界限;除此之外,算法几乎相同.)

我在这里写了一些关于类型推断问题的文章:

http://blogs.msdn.com/b/ericlippert/archive/tags/type+inference/

  • @svick:当必须进行涉及*逆变*转换的泛型类型推断时,上限只能**.由于C#3只有协变或非变量转换,所以没有办法进入甚至*是*上限的情况,所以我们甚至懒得在算法中提及它们.当我们在通用接口和C#4委托上添加协变和逆变转换时,我们在类型推断算法中添加了上限推断. (2认同)

Ily*_*gan 7

可以省略呼叫中的类型

MyClass.MyFunc(p1, p2, 5);
Run Code Online (Sandbox Code Playgroud)

是一个语法糖果(除非你使用匿名类型),它编译完全相同

MyClass.MyFunc<Person, int>(p1, p2, 5);
Run Code Online (Sandbox Code Playgroud)

编译器推断出的值T1T2根据所述类型的参数a,bc.如果p1p2是不兼容的类型(见svick的答案,编译器将无法推断出T1,这将导致一个编译错误.