Eri*_*ert 8

拳击和拆箱是通过延迟还是早期绑定实现的?也就是说,绑定是在运行时还是编译时完成的?

我对这个问题感到有点困惑."绑定"通常用于表示某种分析的结果."早期绑定"通常意味着某些名称在编译时与某些方法槽相关联; "后期绑定"在运行时将名称与插槽相关联.你在拳击的背景下"绑定"是什么意思?

我想你的意思是说,后期绑定仅用于方法和方法调用,而不用于赋值操作/类型转换.为了实现动态绑定,我们使用基类变量引用派生对象.

这不正是我的意思; 我使用方法调用作为一个典型的例子来说明早期和晚期绑定之间的区别.我现在看到你的观点更好了; 精确确定如何执行转换的分析也可以在运行时或编译时完成,因此在某种意义上也是"后期绑定"或"早期绑定"的形式.

我们以此转换为例:

int x = Whatever();
short y = (short)x;
Run Code Online (Sandbox Code Playgroud)

显式转换在编译时完全"绑定".编译器知道操作数是int,目标类型是short,转换将通过将四字节int截断为两个字节的短来执行.转换当然实际上是在运行时执行的.

现在让我们说清楚一点:

int x = Whatever();
short y = checked((short)x);
Run Code Online (Sandbox Code Playgroud)

显式转换在编译时再次绑定.我们知道如何执行操作.但我们也知道在运行时会检查int值以确保它适合短路.

这是否算作你书中的"后期约束"?一些分析在编译时执行,但一些分析在运行时执行.

现在让我们考虑拳击:

int x = Whatever();
object q = x;
Run Code Online (Sandbox Code Playgroud)

这在编译时完全分析.编译器知道q是一个对象而x是一个int,因此它必须发出在运行时将int包装起来的指令.

拆箱怎么样?

int x = Whatever();
object q = x;
int y = (int)q;
Run Code Online (Sandbox Code Playgroud)

在编译时进行了什么分析?我们在编译时知道的是它是一个拆箱转换.实际的类型检查在运行时完成.这是一种"后期绑定"的形式,因为在运行时通过您对后期绑定的定义执行类型检查?

这个怎么样?

int x = Whatever();
object q = x;
int y = (short)q;
Run Code Online (Sandbox Code Playgroud)

这会在运行时抛出异常.在编译时,我们知道它是一个拆箱转换.在运行时我们不做"后期绑定"来说"嘿,我有一个盒装int,让我弄清楚如何将其转换为未装箱的短片".相反,我们说"我们试图将int取消装箱以缩短;抛出异常".盒装T只能打包到T或可空的T.

那么拆箱是"早期约束"还是"后期约束"?它是早期绑定的,因为我们在编译时知道它是一个拆箱转换.它是在运行时进行类型检查的意义上的后期绑定.从某种意义上说,我们不会在运行时重新进行在编译时对int-to-short转换进行的类型分析.

那这个呢?

int x = Whatever();
object q = x;
int y = Convert.ToInt16(q);
Run Code Online (Sandbox Code Playgroud)

要么

int x = Whatever();
dynamic q = x;
int y = (int)q;
Run Code Online (Sandbox Code Playgroud)

现在我们执行所有的分析在运行时; 在这两种情况下,我们在运行时对q进行类型分析,确定q是盒装int,并且"后绑定"转换.

这一切都清楚了吗?很难回答你的问题,因为对于"后期绑定"转换的确切含义,它有点模糊.分析的哪一部分是对你的"约束力"?

  • @Rsk:你基本上是说你想要一个类型分析,不仅要分析声明的编译时类型,还要分析可能在变量中的所有可能的子类型值.这样的功能非常昂贵,因此必须通过其巨大的好处来证明其合理性.我会说,由于两个原因,好处可能很小.1:绝大多数程序都不像你的例子那样容易进行微不足道的分析,2:如果编译器可以识别更严格的类型,那么*用户*也可以.你应该只输入"o"作为"字符串". (2认同)

Gis*_*shu 5

如果你正在寻找的话,拳击在编译时被编入IL指令.

如果您尝试将unbox打包成原始类型以外的类型,则会抛出异常.Ex#1它只是隐式地发生了(值类型为ref类型转换).Ex#2无效的演员阵容在运行时爆炸.

不确定早期或晚期的约束是如何形成的.