object类型

object 类型

object 类型(System.Object)是所有类型的终极父类。任何类型都可以向上转换为 object 类型。

public class Stack
{
    int position;
    object[] data = new object[10];
    public void Push(object obj)
    {
        data[position++] = obj;
    }
    public object Pop()
    {
        return data[--position];
    }
}

由于 Stack 类的操作对象是 object,所以实现 PushPop 任意类型的实例的操作。

Stack stack = new Stack();
stack.Push ("sausage");  // Upcast
string s = (string) stack.Pop();  // Downcast, so explicit cast is needed
Console.WriteLine (s);  // sausage

object 是引用类型,承载了类的优点。但 int 等值类型也可以和 object 类型相互转换并加入栈中。csharp 称这种特性为类型一致化。

stack.Push (3);
int three = (int) stack.Pop();

当值类型和 object 类型相互转换时,公共语言运行时(CLR)必须进行一些特定的工作来对接值类型和引用类型在语义上的差异,这个过程称为装箱(boxing)和拆箱(unboxing)。

1 装箱和拆箱 Boxing and Unboxing

  1. 装箱

    • 装箱是将值类型实例转换为引用类型实例。
    • 引用类型可以是 object 类或接口。
    int x = 9;
    object obj = x;  // Box the int
    

    🎃 一个不可空的值类型装箱之后,其结果是得到一个类型的对象的引用,这里的类型是原式类型装箱后的一种形态:

    int x = 5;
    object o = x;
    

    这里的 o 就是到“装箱的后 int”的一个对象的引用。装箱后的 intint 在 csharp 中其实是看不出来的,即如果调用 o.GetType() 其结果和 typeof(int) 是一样的。

  2. 拆箱

    • 拆箱与装箱相反,它把 object 类型转换为原始的值类型。

      int y = (int)obj;  // Unbox the int
      
    • 拆箱需要显式类型转换。运行时将检查提供的值类型和真实的对象类型是否匹配,并在检查出错时抛出 InvalidCastException

      object obj = 9;  // 9 is inferred to be of type int
      long x = (long) obj;  // InvalidCastException
      

      以下语句是正确的:

      object obj = 9;
      int x = (int)obj;
      
      object obj = 3.5;  // 3.5 is inferred to be of type double
      int x = (int)(double)obj;  // x is now 3
      // (double) 是拆箱操作而 (int) 是数值转换操作
      
    • 装箱转换对系统提供一致性的数据类型至关重要,但该体系不够完美,数组和泛型只支持引用转换,不支持装箱转换。

      object[] a1 = new string[3];  // Legal
      object[] a2 = new int[3];  //Error
      
  3. 装箱和拆箱的复制

    • 装箱是把值类型的实例复制到一个新对象中。
    • 拆箱是把对象的内容复制到一个新的值类型的实例。
    int i = 3;
    object boxed = i;
    i = 5;
    Console.WriteLine(boxed);  // 3
    
    object obj = 3;
    int unboxed = (int)obj;
    obj = 5;
    Console.WriteLine(unboxed);  // 3
    

2 静态和运行时类型检查

csharp 程序在静态(编译时)和运行时(CLR)都会执行类型检查。

  • 静态类型检查使编译器在程序没有运行的情况下检查程序的正确性。例如,因为编译器会强制进行静态类型检查因而以下代码会出错:

    int x = "5";
    
  • 运行时的类型检查有 CLR 执行,在使用引用类型转换或者拆箱操作进行向下类型转换时发生:

    object y = "5";
    int x = (int)y;  // Runtime error, downcast failed
    

    运行时可以进行类型检查是因为堆(Heap)上的每一个对象都在内部存储了类型标识,这个标识可以通过 object 类的 GetType 方法得到。

3 GetType 方法和 typeof 操作符

csharp 所有类型在运行时都以 System.Type 类的实例表示,两种基本方法可以获得 System.Type 对象:

  • 在类型实例上调用 GetType 方法。
  • 在类型名称上使用 typeof 操作符。
  • GetType 是在运行时被计算出的。
  • typeof 是在编译时静态计算出的(如果是使用泛型类型参数,那么它将由即时编译器(JIT)解析)。
    ☀️ System.Type拥有诸多属性,例如类型的名称、程序集、基类型等属性:
class Point  {public int x, y;}

class Program
{
    static void Main(string[] args)
    {
        Point p = new Point();
        Console.WriteLine(p.GetType().Name);  // Point
        Console.WriteLine(typeof(Point).Name);  // Point
        Console.WriteLine(p.GetType() == typeof(Point));  // true
        Console.WriteLine(p.x.GetType().Name);  // Int32
        Console.WriteLine(p.y.GetType().FullName);  // System.Int32
    }
}

🌴 当在值类型上调用 GetType() 方法时,这个值类型首先必须装箱。对可空值类型来说,它要么引起 NullReferenceException 异常,要么返回底层的非可空值类型。

int? noValue = null;
Console.WriteLine(noValue.GetType());  // NullReferenceException

int? hasValue = new int?(5);
Console.WriteLine(hasValue.GetType());  // System.Int32

4 ToString 方法

ToString 方法返回类型实例的默认文本描述。所有内置类型都重写了方法。

int x = 1;
string s = x.ToString();  // s is "1"

可以使用下面的方法在自定义的类中重写 ToString 方法:

public class Panda
{
    public string name;
    public override string ToString() => name;
}

Panda p = new Panda {name = "Petey"};
Console.WriteLine(p.ToString());  // Petey

如果不重写 ToString 方法,将返回类型的名称。
🍂 当直接在值类型对象上调用 ToString 这样的 object 成员时,若改成员是重写的则不会发生装箱。只有进行类型转换时才会执行装箱操作:

int x = 1;
string s1 = x.ToString();  // Calling on nonboxed value
object box = x;
string s2 = box.ToString();  // Calling on boxed value
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值