1.参考《C# 语言规范》
装箱和拆箱的概念是 C# 的类型系统的核心。它在 value-type 和 reference-type 之间的架起了一座桥梁,使得任何 value-type 的值都可以转换为 object 类型的值,反过来转换也可以。装箱和拆箱使我们能够统一地来考察类型系统,其中任何类型的值最终都可以按对象处理。
将 value-type 的一个值装箱包括以下操作:分配一个对象实例,然后将 value-type 的值复制到该实例中。
最能说明 value-type 的值的实际装箱过程的办法是,设想有一个为该类型设置的装箱类 (boxing class)。对任何 value-type 的 T 而言,装箱类的行为可用下列声明来描述:
sealed class T_Box: System.ValueType
{
T value;
public T_Box(T t) {
value = t;
}
}
T 类型值 v 的装箱过程现在包括执行表达式 new T_Box(v) 和将结果实例作为 object 类型的值返回。因此,下面的语句
int i = 123;
object box = i;
在概念上相当于
int i = 123;
object box = new int_Box(i);
实际上,像上面这样的 T_Box 和 int_Box 并不存在,并且装了箱的值的动态类型也不会真的属于一个类类型。相反,T 类型的装了箱的值属于动态类型 T,若用 is 运算符来检查动态类型,也仅能引用类型 T。例如,
int i = 123;
object box = i;
if (box is int) {
Console.Write("Box contains an int");
}
将在控制台上输出字符串“Box contains an int”。
装箱转换隐含着复制一份待装箱的值。这不同于从 reference-type 到 object 类型的转换,在后一种转换中,转换后的值继续引用同一实例,只是将它当作派生程度较小的 object 类型而已。例如,已知下面的声明
struct Point
{
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
则下面的语句
Point p = new Point(10, 10);
object box = p;
p.x = 20;
Console.Write(((Point)box).x);
将在控制台上输出值 10,因为将 p 赋值给 box 是一个隐式装箱操作,它将复制 p 的值。如果将 Point 声明为 class,由于 p 和 box 将引用同一个实例,因此输出值为 20。
一个拆箱操作包括以下两个步骤:首先检查对象实例是否为给定 value-type 的一个装了箱的值,然后将该值从实例中复制出来。
参照前一节中关于假想的装箱类的描述,从对象 box 到 value-type T 的拆箱转换相当于执行表达式 ((T_Box)box).value。因此,下面的语句
object box = 123;
int i = (int)box;
在概念上相当于
object box = new int_Box(123);
int i = ((int_Box)box).value;
为使到给定 value-type 的拆箱转换在运行时取得成功,源操作数的值必须是对某个对象的引用,而该对象先前是通过将该 value-type 的某个值装箱而创建的。如果源操作数为 null,则将引发 System.NullReferenceException。如果源操作数是对不兼容对象的引用,则将引发 System.InvalidCastException。
2.~ 运算符对操作数执行按位求补运算,其效果相当于反转每一位。按位求补运算符是为 int、uint、long 和 ulong 类型预定义的。
简单来说,就是取反。
3.const 关键字用于修改字段或局部变量的声明。它指定字段或局部变量的值是常数,不能被修改。例如:
const int x = 0;
public const double gravitationalConstant = 6.673e-11;
private const string productName = "Visual C#";
readonly 关键字是可以在字段上使用的修饰符。当字段声明包括 readonly 修饰符时,该声明引入的字段赋值只能作为声明的一部分出现,或者出现在同一类的构造函数中。在此示例中,字段 year 的值无法在 ChangeYear 方法中更改,即使在类构造函数中给它赋了值。
程序代码:
class Age
{
readonly int _year;
Age(int year)
{
_year = year;
}
void ChangeYear()
{
_year = 1967; // Will not compile.
}
}
readonly 关键字与 const 关键字不同。const 字段只能在该字段的声明中初始化。readonly 字段可以在声明或构造函数中初始化。因此,根据所使用的构造函数,readonly 字段可能具有不同的值。另外,const 字段为编译时常数,而 readonly 字段可用于运行时常数。