zoukankan      html  css  js  c++  java
  • 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(); // 调用的就是装箱后的值
  • 相关阅读:
    python并发编程之多进程
    python并发编程之多进程理论部分
    Python GIL(Global Interpreter Lock)
    python并发编程之多线程
    前端基础之CSS
    前端知识之HTML内容
    Python杂货铺-(1)os模块在python中执行shell命令
    Hive学习小记-(17)inline(array(struct))与explode
    Hive学习小记-(16)hive加载解析json文件
    Hive学习小记-(15)transform函数
  • 原文地址:https://www.cnblogs.com/njabsky/p/13582579.html
Copyright © 2011-2022 走看看