简单类型

简单类型就是组成应用程序中的基本构件的类型,例如,数值和布尔值( truefalse )。简单类型与复杂类型不同,没有子类型或特性。大多数简单类型都是存储数值的,初看起来有点奇怪,使用一种类型来存储数值不可以吗?

  有很多数值类型是因为在计算机内存中,把数字作为一系列的0和1来存储。对于整数值,用一定的(单个数字,可以是0或1)来存储,用二进制格式来表示。以N位来存储的变量可以表示任何介于0到(2N-1)之间的数。大于这个值的数因为太大,所以无法存储在这个变量中。

  例如,有一个变量存储了2位,在整数和表示该整数的位之间的映射应如下所示:

    0 = 00
    1 = 01
    2 = 10
    3 = 11

  如果要存储更多数字,就需要更多的位(例如,3位可以存储0~7的数)。
  这样得到的结论是要存储每个可以想象得到的数,就需要非常多的位,这并不适合PC。即使可以用足够多的位来表示每一个数,用这么多的位存储一个表示范围很小的变量(例如0~10)的效率非常低下,因为存储器被浪费了。其实表示0~10之间的数,4位就足够了,这样就可以用相同的内存空间存储这个范围内的更多数值。

  相反,许多不同的整数类型可用于存储不同范围的数值,占用不同的内存空间(至多64位),这些类型 如表3-1所示

类型 别名 允许的值
sbyte System.SByte 介于 -128 ~ 127 之间的整数
byte System.Byte 介于0 ~ 255 之间的整数
short System.Int16 介于 -32 768 ~ 32 767 之间的整数
ushort System.UInt16 介于 0 ~ 65 535 之间的整数
int System.Int32 介于 -2 147 483 648 ~ 2 147 483 647 之间的整数
uint System.UInt32 介于 0 ~ 4 294 967 295 之间的整数
long System.Int64 介于 -9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807 之间的整数
ulong System.UInt64 介于 0 ~ 18 446 744 073 709 551 615 之间的整数

表 3-1 整数类型

这些类型中的每一种都利用了 .NET Framework 中定义的标准类型。如第1章所述,使用标准类型可以在语言之间交互操作。在C#中这些类型的名称是Framework中定义的类型的别名,表3-1 列出了这些类型在 .NET Framework 库中的名称。

  一些变量名称前面的 “u” 是 unsigned 的缩写,表示不能在这些类型的变量中存储负数,参见该表中的“允许的值”一列。

  当然,还需要存储浮点数,它们不是整数。可以使用的浮点数变量类型有3种: floatdoubledecimal。前两种可以用 +/- mx2e的形式存储浮点数,m 和 e 的值因类型而异。decimal使用另一种形式: +/- mx10e。这3种类型、其 m 和 e 的值,以及它们在实数中的上下限如 表3-2所示

类型 别名 m的最小值 m的最大值 e的最小值 e的最大值 近似的最小值 近似的最大值
float System.Single 0 224 -149 104 1.5 x 10-45 3.4 x 1034
double System.Double 0 253 -1075 970 5.0 x 10-324 1.7 x 10308
decimal System.Decimal 0 2% -28 0 1.0 x 10-28 7.9 x 1028

表3-2 浮点类型

  除数值类型外,另外还有3种简单类型,如表3-3所示

类型 别名 允许的值
char System.Char 一个 Unicode字符,存储 0~65 535 之间的整数
bool System.Boolean 布尔值: true 或 false
string System.String 一组字符

表3-3 文本和布尔类型

  注意 ⚠️ 组成 string 的字符数量没有上限,因为它可以使用可变大小的内存。

  布尔类型 bool 是 C# 中最常用的一种变量类型,类似的类型在其他语言的代码中非常丰富。当编写应用程序的逻辑流程时,一个可以是 truefalse 的变量有非常重要的分支作用。例如,考虑一下有多少问题可以用 true(或 yes 和 no)来回答。执行变量值之间的比较或检查输入的有效性就是后面使用布尔变量的两个编程示例。

  介绍了这些类型后,下面用一个简短示例来声明和使用它们。在下面的示例中,要使用一些简单的代码来声明两个变量,给它们赋值,再输出这些值。

在 Program.cs 中添加如下代码:

    static void Main(string[] args)
    {
        int myInteger;
        string myString;
        myInteger = 17;
        myString = "\"myInteger\" is";
        Console.WriteLine( "{0} {1}", myString, myInteger );
        Console.ReadKey(); 
    }

示例的说明

我们添加的代码完成了以下3项任务:

  • 声明两个变量
  • 给这两个变量赋值
  • 将两个变量的值输出到控制台
    变量声明使用下述代码:
    int myInteger;
    string myString;

  第一行声明一个类型为 int 的变量 myInteger,第二行声明一个类型为 string 的变量 myString。

变量的命名是有限制🚫的,不能使用任意的字符序列。 “变量的命名” 一节将介绍变量的命名规则。

  接下来的两行代码为变量赋值:

    接下来的两行代码为变量赋值:
    myInteger = 17;
    myString = "\"myInteger\" is";

  使用 = 赋值运算符(在本章的 “表达式” 一节中将详细介绍)给变量分配两个固定的值(在代码中称为字面值)。把整数值 17 赋给 myInteger,把字符串 \“myInteger\” is (包括引号)赋给 myString。

  以这种方式给字符串赋予字面值时,必须用双引号把字符串括起来。因此,如果字符串本身包含双引号,就会出现错误,必须用一些表示这些字符的其他字符(即转义序列)来替代它们。本例使用序列 \" 来转义双引号:

    myString = "\"myInteger\" is";
    如果不使用这些转义序列,而输入如下代码:
    myString = ""myInteger" is";  ❌
    就会出现编译错误。

  注意 ⚠️ 给字符串赋予字面值时,必须小心换行 --- C#编译器会拒绝分布在多行上的字符串字面值。要添加一个换行符,可在字符串中使用换行符的转义序列,即 \n。例如,赋值语句:

    myString = "This string has a\nline break.";

    会在控制台视图中显示两行代码,如下所示:
    This string has a
    line break.

  所有转义序列都包含一个反斜杠符号,后跟一个字符组合(详见后面的内容),因为反斜杠符号的这种用途,它本身也有一个转义序列,即两个连续的反斜杠 \\

下面继续解释代码,还有一行没有说明:

    Console.WriteLine("{0} {1}.", myString, myInteger);

  它看起来类似于第一个示例中把文本写到控制台上的简单方法,但本例指定了变量。这里不详细讨论这行代码,只需要知道这是本书第I部分用于给控制台窗口输出文本的一种技巧。在括号中,有如下两项:

  • 一个字符串* 一个用逗号分隔的变量列表,这些变量的值将插入到输出字符串中

  输出字符串是 "{0} {1}.",看上去它们并没有包含有用的文本。但是前面看到过,这并不是我们运行代码时实际看到的结果,其原因是:字符串实际上是插入变量的一个模版,字符串中的每对花括号都是一个占位符,包含列表中每个变量的内容。每个占位符(或格式字符串)用包含在花括号中的一个整数来表示。整数从0开始,每次递增1,占位符的总数应等于列表中指定的变量数,变量列表用逗号隔开,跟在字符串后。把文本输出到控制台时,每个占位符就会用每个变量的值来替代。在上面的示例中,{0}用第一个变量的值 myString 替换,{1}用 myInteger 的内容来替换。

  在后面的示例中,就使用这种给控制台输出文本的方式显示代码的输出结果。最后一行代码在前面的示例中也出现过,用于在程序结束前等待用户输入内容:

    Console.ReadKey();

  这里不详细讨论这行代码,但后面的示例会常常用到它。现在只需要知道,它暂停代码的执行,等待用户按下一个键。

🔚