CLR Via C#: 基元类型、引用类型和值类型

编程语言的基元类型 - 编译器直接支持的数据类型

基元类型直接映射到Framework类库(FCL)中存在的类型

            int a1 = 0;
            System.Int32 a2 = 0;
            int a3 = new int();
            System.Int32 a4 = new System.Int32();        

C#基元类型:

  • sbyte
  • byte
  • short
  • ushort
  • int
  • uint
  • long
  • ulong
  • char
  • float
  • double
  • bool
  • decimal
  • string
  • object
  • dynamic

编译器能执行基元类型之间的隐式或显示转换。只有在转换“安全”的时候,C#允许隐式转换。所谓“安全”,是指不会发生数据丢失的情况。“不安全”意味着在转换之后,有可能丢失精度或者数量级。

除了转型,基本类型还能写成文本常亮。

Console.WriteLine(123.ToString() + 456.ToString()); //"123456"

 

checked和unchecked基元类型操作

对基元类型执行的许多算术运算都可能造成溢出。

Byte b = 100;
            b = (Byte)(b + 200);
            Console.WriteLine(b); // 44
            Console.ReadLine();

 让C#编译器控制溢出的一个办法是使用/checked+编译器开关。这个开关只是编译器在生成代码是,使用加、减、乘和转换指令的溢出检测版本。除了全局性的打开或关闭溢出检测,程序员还可以在代码的指定区域控制溢出检测。

 

UInt32 invalid = unchecked((UInt32)(-1));
            Console.WriteLine(invalid);
            Console.ReadLine();

 

UInt32 invalid = checked((UInt32)(-1)); // OverflowException
            Console.WriteLine(invalid);
            Console.ReadLine();

 

checked {
                Byte b = 100;
                b = (Byte)(b + 200);
            }

 

引用类型和值类型

  1. 引用另一篇博客中的一句话:值类型就是现金,要用直接用;引用类型是存折,要用还得先去银行取现。
  2. 值类型的实例一般在线程栈上分配。在代表值类型实例的一个变量中,并不包含一个指向实例的指针。相反,变量中包含了实例本身的字段。
  3. 在文档中查看一个类型时,任何称为“类”的类型都是引用类型,文档将所有值类型都成为结构或枚举
  4. 引用类型,string和class统称为引用类型,当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。当使用new创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的小空间中。
  5. 两者的主要区别:
    • 值类型的内存空间分配在栈上;而引用类型的内存空间分配在堆上
    • 栈的内存分配时自动释放;而堆的内存是有GC(垃圾回收)来释放
    • 值类型存取速度快,引用类型存取速度慢
    • 值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针或引用
    • 值类型继承自System.ValueType (ValueType是继承自System.Object的),引用类型继承自System.Object
    • 引用类型的Equals方法默认比较地址,而值类型的默认比较值
    • 引用类型可以派生出新的类型,而值类型不能
    • 引用类型可以设置为null值,值类型一般不能(只有Nullable<T>可以设置为null值)
    • 引用类型变量的赋值只复制对对象的引用,而不复制对象本身。而将一个值类型变量赋给另一个值类型变量时,将复制对象
    • 值类型一旦定义,则不可以变
    class Program
    {
        static void Main(string[] args)
        {
            SomeRef r1 = new SomeRef(); //在堆上分配
            SomeVal v1 = new SomeVal(); //在栈上分配
            r1.x = 5;
            v1.x = 5;
            Console.WriteLine(r1.x);
            Console.WriteLine(v1.x);

            SomeRef r2 = r1;    // 5
            SomeVal v2 = v1;    // 5
            r1.x = 8;
            v1.x = 9;
            Console.WriteLine(r1.x);    // 8
            Console.WriteLine(r2.x);    // 5
            Console.WriteLine(v1.x);    // 9
            Console.WriteLine(v2.x);    // 5
            Console.ReadLine();
        }
    }

    //引用类型,由于使用了‘class’
    class SomeRef { public Int32 x; }

    //值类型,由于使用了'struct'
    struct SomeVal { public Int32 x; }



posted on 2022-03-08 14:52  LilianChen  阅读(50)  评论(0编辑  收藏  举报

导航