1

例如:

int i=10;
object o = i; //late or early??

相似地,

object o = "11";
int i = (int)o;//late or early??
4

4 回答 4

8

装箱和拆箱是通过后期绑定还是提前绑定实现的?也就是说,绑定是在运行时还是编译时完成的?

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

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

这不是我的意思。我将方法调用用作说明早期绑定和后期绑定之间区别的规范示例。我现在更好地理解了你的观点;精确确定如何执行转换的分析也可以在运行时或编译时完成,因此在某种意义上也是“后期绑定”或“早期绑定”的一种形式。

让我们以这种转换为例:

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,然后“后期绑定”转换。

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

于 2011-12-07T17:21:18.707 回答
5

如果这是您正在寻找的内容,则在编译时将装箱放入 IL 指令中。

如果您尝试将其拆箱为原始类型以外的类型,则会引发异常。Ex#1 它只是隐式地装箱(值类型到 ref 类型转换)。Ex#2 无效的演员阵容在运行时爆炸。

不确定多早或多晚绑定进入图片。

于 2011-12-07T04:14:40.903 回答
4

编译器将发出装箱指令,您可以在 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     

在第二个版本中,这只会爆炸。字符串类型的对象不能转换为整数。

于 2011-12-07T04:14:34.723 回答
1

C# 编译在运行时执行的指令。

装箱需要(并非不可忽视的)运行时成本;装箱和拆箱可能会导致运行时错误(如您的示例“int i = (int)o”所示)。

“后期绑定”与“早期绑定”意味着某些东西是“动态的”(例如,某些对象的虚拟方法的运行时绑定)。在这种情况下,拳击是“固定的”。所以我想你可以说它是“早期绑定”。

于 2011-12-07T04:17:53.787 回答