例如:
int i=10;
object o = i; //late or early??
相似地,
object o = "11";
int i = (int)o;//late or early??
装箱和拆箱是通过后期绑定还是提前绑定实现的?也就是说,绑定是在运行时还是编译时完成的?
我对这个问题有点困惑。“绑定”通常用于表示某种分析的结果。“早期绑定”通常意味着某个名称在编译时已与某个方法槽相关联;“后期绑定”在运行时将名称与插槽相关联。在拳击的背景下,这里的“绑定”是什么意思?
我猜你的意思是说后期绑定只对方法和方法调用起作用,而不是对赋值操作/类型转换起作用。为了实现动态绑定,我们使用基类变量引用派生对象。
这不是我的意思。我将方法调用用作说明早期绑定和后期绑定之间区别的规范示例。我现在更好地理解了你的观点;精确确定如何执行转换的分析也可以在运行时或编译时完成,因此在某种意义上也是“后期绑定”或“早期绑定”的一种形式。
让我们以这种转换为例:
int x = Whatever();
short y = (short)x;
该显式转换在编译时完全“绑定”。编译器知道操作数是 int,目标类型是 short,转换将通过将四字节 int 截断为两字节 short 来执行。当然,转换实际上是在运行时执行的。
现在让我们让它不太清楚:
int x = Whatever();
short y = checked((short)x);
显式转换在编译时再次绑定。我们知道操作将如何执行。但我们也知道,在运行时会检查 int 值以确保它适合 short。
这算作你书中的“后期装订”吗?有些分析是在编译时执行的,但有些分析是在运行时执行的。
现在让我们考虑拳击:
int x = Whatever();
object q = x;
这在编译时完全分析。编译器知道 q 是一个对象,而 x 是一个 int,因此它必须在运行时发出将 int 装箱的指令。
开箱呢?
int x = Whatever();
object q = x;
int y = (int)q;
编译时做了什么分析?我们在编译时只知道这是一个拆箱转换。实际的类型检查是在运行时完成的。这是“后期绑定”的一种形式,因为根据您对后期绑定的定义,类型检查是在运行时执行的?
这个怎么样?
int x = Whatever();
object q = x;
int y = (short)q;
这会在运行时引发异常。在编译时我们知道这是一个拆箱转换。在运行时,我们不会做“后期绑定”来说“嘿,我有一个装箱的 int,让我弄清楚如何将它转换为未装箱的短”。相反,我们说“我们正在尝试将 int 拆箱为 short;抛出异常”。装箱的 T 只能拆箱为 T 或可为空的 T。
那么拆箱是“早期绑定”还是“后期绑定”?从某种意义上说,它是早期绑定,我们在编译时就知道这是一个拆箱转换。从我们在运行时进行类型检查的意义上说,它是后期绑定的。从某种意义上说,我们不会在运行时重新进行类型分析,这并不是迟到的限制,而这种分析在编译时会为 int-to-short 转换完成。
那这个呢?
int x = Whatever();
object q = x;
int y = Convert.ToInt16(q);
或者
int x = Whatever();
dynamic q = x;
int y = (int)q;
现在我们确实在运行时执行了所有这些分析;在这两种情况下,我们都会在运行时对 q 进行类型分析,确定 q 是一个装箱的 int,然后“后期绑定”转换。
这一切都清楚了吗?很难回答您的问题,因为对于“后期绑定”转换的确切含义有点模糊。分析的哪一部分对你有“约束力”?
如果这是您正在寻找的内容,则在编译时将装箱放入 IL 指令中。
如果您尝试将其拆箱为原始类型以外的类型,则会引发异常。Ex#1 它只是隐式地装箱(值类型到 ref 类型转换)。Ex#2 无效的演员阵容在运行时爆炸。
不确定多早或多晚绑定进入图片。
编译器将发出装箱指令,您可以在 IL 中看到这些指令。给定代码
int item = 10;
object obj = item;
item = (int)obj;
你会编译成类似的东西
IL_0000: ldc.i4.s 0A
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: box System.Int32
IL_0009: stloc.1
IL_000A: ldloc.1
IL_000B: unbox.any System.Int32
IL_0010: stloc.0
在第二个版本中,这只会爆炸。字符串类型的对象不能转换为整数。
C# 编译在运行时执行的指令。
装箱需要(并非不可忽视的)运行时成本;装箱和拆箱可能会导致运行时错误(如您的示例“int i = (int)o”所示)。
“后期绑定”与“早期绑定”意味着某些东西是“动态的”(例如,某些对象的虚拟方法的运行时绑定)。在这种情况下,拳击是“固定的”。所以我想你可以说它是“早期绑定”。