C#是微软推出的类似C++和Java一种面向对象的语言,运行于.NET Framework框架(本人对.NET Framework一窍不通)之上的高级语言,它有很多特性类似于Java,比如单继承、接口等,同时也是一种简单的、通用的、现代的编程语言。

C#中的值类型和引用类型

理解值类型和引用类型非常重要,从概念上看,它们两个的区别是值类型直接存储其值,引用类型则存储对值的引用。这两种类型存储在内存不同的地方,值类型存储在堆栈中 ,引用类型存储在托管堆上。所以需要区别某个类型是引用类型还是值类型。存储位置的不同会有不同的影响。

例如,int是值类型,下面的语句会在内存的两个地方存储值。

int i = 10;

j = i;

再看下面代码,假如已经定义了一个类User:

1
2
3
4
5
6
7
User user1,user2;
user1 = new User();
user1.age = 20;
user2 = user1;
Console.WriteLine(user2.age);
user2.age = 30;
Console.WriteLine(user1.age);

上面代码创建了一个User对象的两个引用,并不会实例化给定类型的对象, 和Java类似,要创建对象分配内存空间就要使用new关键字,如上代码中,user1和user2引用同一个对象,所以user2的修改会影响user1,反之依然。所以程序会输出20和30。

CTS类型

需要注意的是,C#认可的基本预定义类型并没有内置于C#中,它内置于.NET Framework中。比如在C#中声明一个int类型,实际上是声明了一个.NET结构中的System.Int32的一个实例。据说这样没有性能损失,因为这看起来似乎是吧基本数据类型看作是支持某些方法的类,例如把int类型转换成string类型,可以写成如下形式:

string s = i.ToString();

需要注意的是,这种便利的语法背后,类型实际仍存储为基本类型。基本类型在概念上用.NET结构表示,所以没有性能损失(为什么没有性能损失,暂时还不理解)。

C#中的预定义类型

在C#中一共有15个预定义类型,其中13个是值类型,2个引用类型(string和object)。

  1. 值类型

    内置的CTS值类型表示基本类型,如整形和浮点类型,字符类型和布尔类型。

    • 整型

      C#支持8个预定义整型类型,如下表所示:

      | 名称 | CTS类型 | 说明 | 范围 |
      | :—-: | :———–: | :——: | :———–: |
      | sbyte | System.SByte | 8位有符号整数 | -128~127 |
      | short | System.Int16 | 16位有符号整数 | -32768~32767 |
      | int | System.Int32 | 32位有符号整数 | -2^31~-2^31-1 |
      | long | System.Int64 | 64位有符号整数 | -2^63~-2^63-1 |
      | byte | System.UByte | 8位无符号整数 | 0~2^8-1 |
      | ushort | System.UInt16 | 16位无符号整数 | 0~2^16-1 |
      | uint | System.UInt32 | 32位无符号整数 | 0~2^32-1 |
      | ulong | System.UInt64 | 64位无符号整数 | 0~2^64-1 |

这里还需要注意,C#数据类型的名称和C++、java类型一致,但是定义不同,在C#中,int总是32位带符号的整数,而在C++中,int的位数取决于平台。C#中所有的数据类型都与平台无关,这是为C#和.NET迁移到其他平台做准备。

byte是0-255的标准8位类型,但是在强调类型安全时,C#认为byte类型和char类型完全不同,他们之间的编程转换必须显式写出。而且byte在默认状态下是无符号的。

  1. 浮点类型

    如下表:

    | 名称 | CTS类型 | 说明 | 位数 | 范围(大致) |
    | :—-: | :———–: | :——-: | :—: | :———————-: |
    | float | System.Single | 32位单精度浮点数 | 7 | ±1.5×10^-45~±3.4×10^38 |
    | double | System.Double | 64位双精度浮点数 | 15/16 | ±5.0×10^-324~±1.7×10^308 |

    在代码中如果没有对某个非整数值硬编码,则编译器一般嘉定该变量是double。如果指定为float则可以写成如下格式:

    float f = 12.3F;

    更高精度的浮点数:decimal

    | 名称 | CTS类型 | 说明 | 位数 | 范围(大致) |
    | :—–: | :————: | :————: | :–: | :——————–: |
    | decimal | System.Decimal | 128位高精度十进制树表示法 | 28 | ±1.0×10^-28~±7.9×10^28 |

    CTS和C#一个重要的优点就是提供了一个专用类型进行财务计算,它就是decimal类型。使用这种类型取决于用户。但应注意,decimal类型不是基本类型,所以在使用此类型进行计算时会有性能损失。

    要定义一个decimal类型如下所示:

    decimal d = 12.30M;

  2. 布尔类型

    | 名称 | CTS类型 | 说明 | 位数 | 范围(大致) |
    | :–: | :————: | :———-: | :–: | :——–: |
    | bool | System.Boolean | 表示true或false | NA | true或false |

    bool值和整数值不能隐式转换,如果变量声明为bool类型,则只能使用true或这false。如果试图使用0作为false,或者非0值作为true作为返回类型为bool的方法返回值,就会出错。

  3. 字符类型

    | 名称 | CTS类型 | 说明 |
    | :–: | :———: | :—————–: |
    | char | System.Char | 表示一个16位的(Unicode)字符 |

    char类型的字面量用单引号括起来,如‘A’,如果放在双引号中,编译器会把它看成字符串,从而产生错误。

  4. string类型

    先看代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    static void Main(string[] args)
    {
    string s1 = "Hello world";
    string s2 = s1;
    Console.WriteLine("s1 is:" + s1);
    Console.WriteLine("s2 is:" + s2);

    s1 = "Hello C Sharp";
    Console.WriteLine("s1 is:" + s1);
    Console.WriteLine("s2 is:" + s2);

    Console.ReadLine();
    return;
    }

    string虽然也是引用类型,但是当更改string对象的内容时,并不是修改了原来的内容,而是在堆中重新创建了一个新的string对象。这和之前理解的引用似乎相反。这是因为字符串时不可改变的,修改其中任何一个字符串,就会创建一个新的对象。