C#中的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]; }
}

这是一个后进先出的这么一个栈,因为是object类型,所以你可以Push和Pop任意的类型到这个栈里

Stack stack = new Stack();
stack.Push ("sausage");
string s = (string) stack.Pop(); // 向下转换,显式的转换一下

Console.WriteLine (s); // sausage

object是引用类型,但值类型可以转换为object,反之亦然。(类型统一)

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

在值类型和object之间转换的时候,CLR必须执行一些特殊的工作,以弥补值类型和引用类型之间语义上的差异,这个过程就叫做装箱和拆箱。

装箱(boxing)

装箱就是把值类型的实例转换为引用类型的实例的动作,目标引用类型可以是object,也可以是某个接口

int x = 9;
object obj = x; // 把int值装箱

拆箱(unboxing)

拆箱正好和装箱相反,把对象转换为原来的值类型

int y = (int)obj; // 还原int值

拆箱需要显式的转换

拆箱过程中,运行时会检查这个值类型和object对象的真实类型是否匹配,如果不匹配就抛出InvalidCastException

object obj = 9; // 9 在这里是int类型
long x = (long) obj; // InvalidCastException

下面的转换就是可以的,int类型可以隐式的转换为long类型,但是像上面的直接拆箱就不可以:

object obj = 9;
long x = (int) obj;

装箱对于类型统一是非常重要的,但是系统设计还是不够完美,比如数组和泛型只支持引用转换,不支持装箱

object[] a1 = new string[3]; // 可以的
object[] a2 = new int[3]; // 会报错

装箱拆箱的复制

  • 装箱会把值类型的实例复制到一个新的对象
  • 拆箱会把这个对象的内容再复制给一个值类型的实例

看个例子:

int i = 3;
object boxed = i;
i = 5;
Console.WriteLine (boxed); // 3

静态和运行时类型检查

C#的程序既会做静态的类型检查(编译时),也会做运行时的类型检查(CLR)

静态检查:就是不运行程序的情况下,让编译器保证你的程序的正确性,比如 int x = "5"; 这么写肯定是不行的

运行时的类型检查由CLR执行,发生在向下的引用转换或拆箱的时候。

object y = "5";
int z = (int) y; // 运行时报错,向下转换失败

运行时检查之所以可行是因为每个在heap上的对象内部都存储了一个类型token。这个token可以通过调用object的GetType()方法来获取。

GetType方法与typeof操作符

所有C#的类型在运行时都是以System.Type的实例来展现的

有两种方式可以获得System.Type对象:一是在实例上调用GetType()方法;第二个是在类型名上使用typeof操作符。

GetType是在运行时被算出的,typeof是在编译时被算出的(静态)(当涉及到泛型类型参数时,它是由JIT编译器来解析的)

System.Type

System.Type的属性有:类型名称、Assembly、基类等等。直接看例子:

using System;
public class Point { public int X, Y; }
class Test
{
    static void Main()
    {
        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
    }
}

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); // Petey

当你调用一个被重写的object成员的时候,例如在值类型上直接调用ToString()方法,这时候就不会发生装箱操作,但是如果你进行了转换,那么装箱操作就会发生

int x = 1;
string s1 = x.ToString(); // 这里就没有发生装箱
object box = x;
string s2 = box.ToString(); // 调用的就是装箱后的值
原文地址:https://www.cnblogs.com/njabsky/p/13582579.html