ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# C# 数据类型 > 原文: [https://zetcode.com/lang/csharp/datatypes/](https://zetcode.com/lang/csharp/datatypes/) 在 C# 教程的这一部分中,我们将讨论数据类型。 计算机程序(包括电子表格,文本编辑器,计算器或聊天客户端)可以处理数据。 用于各种数据类型的工具是现代计算机语言的基本组成部分。 数据类型是一组值以及对这些值的允许操作。 ## C# 数据类型 数据类型是一组值,以及对这些值的允许操作。 C# 中的两种基本数据类型是值类型和引用类型。 基本类型(字符串除外),枚举,元组和结构是值类型。 类,字符串,接口,数组和委托是引用类型。 每种类型都有一个默认值。 引用类型在堆上创建。 引用类型的生存期由 .NET 框架管理。 引用类型的默认值为空引用。 分配给引用类型的变量会创建引用的副本,而不是引用值的副本。 值类型在栈上创建。 生存期由变量的生存期决定。 分配给值类型的变量会创建要分配的值的副本。 值类型具有不同的默认值。 例如,布尔默认值为`false`,十进制为 0,字符串为空字符串`""`。 ## C# 布尔值 我们的世界建立了双重性。 有天地,水火,阴阳,男人和女人,爱与恨。 在 C# 中,`bool`数据类型是具有以下两个值之一的原始数据类型:`true`或`false`。 这是一种基本数据类型,在计算机程序中非常常见。 快乐的父母正在等待孩子的出生。 他们为两种可能性都选择了名称。 如果要成为男孩,他们选择了约翰。 如果要成为女孩,他们会选择维多利亚。 `Program.cs` ```cs using System; namespace BooleanType { class Program { static void Main(string[] args) { Random random = new Random(); bool male = Convert.ToBoolean(random.Next(0, 2)); if (male) { Console.WriteLine("We will use name John"); } else { Console.WriteLine("We will use name Victoria"); } } } } ``` 该程序使用随机数生成器来模拟我们的情况。 ```cs Random random = new Random(); ``` 我们创建一个`Random`对象,该对象用于计算随机数。 它是系统名称空间的一部分。 ```cs bool male = Convert.ToBoolean(random.Next(0, 2)); ``` `Next()`方法返回指定范围内的随机数。 下限包括在内,上限不包括在内。 换句话说,我们收到 0 或 1。随后`Convert()`方法将这些值转换为布尔值,0 转换为`false`,1 转换为`true`。 ```cs if (male) { Console.WriteLine("We will use name John"); } else { Console.WriteLine("We will use name Victoria"); } ``` 如果将`male`变量设置为`true`,我们选择名称 John。 否则,我们选择名称 Victoria。 诸如`if/else`语句之类的控制结构可使用布尔值。 ```cs $ dotnet run We will use name John $ dotnet run We will use name John $ dotnet run We will use name Victoria ``` 多次运行该程序将给出此示例输出。 ## C# 整数 整数是实数的子集。 它们写时没有小数或小数部分。 整数落在集合`Z = {..., -2, -1, 0, 1, 2, ...}`中。 整数是无限的。 在计算机语言中,整数是原始数据类型。 实际上,计算机只能使用整数值的子集,因为计算机的容量有限。 整数用于计算离散实体。 我们可以有 3、4、6 个人,但不能有 3.33 个人。 我们可以有 3.33 公斤。 | C# 别名 | .NET 类型 | 大小 | 范围 | | --- | --- | --- | --- | | `sbyte` | `System.SByte` | 1 字节 | -128 至 127 | | `byte` | `System.Byte` | 1 字节 | 0 至 255 | | `short` | `System.Int16` | 2 字节 | -32,768 至 32,767 | | `ushort` | `System.UInt16` | 2 字节 | 0 至 65,535 | | `int` | `System.Int32` | 4 字节 | -2,147,483,648 至 2,147,483,647 | | `uint` | `System.UInt32` | 4 字节 | 0 至 4,294,967,295 | | `long` | `System.Int64` | 8 字节 | -9,223,372,036,854,775,808 至 9,223,372,036,854,775,807 | | `ulong` | `System.UInt64` | 8 字节 | 0 至 18,446,744,073,709,551,615 | 可以根据我们的需要使用这些整数类型。 没有人(也许有些圣经人除外)的年龄可以超过 120、130 岁。 然后,我们可以在程序中将`byte`类型用于年龄变量。 这样可以节省一些内存。 ### 离散实体 如果我们使用整数,那么我们将处理离散实体。 我们将使用整数来计算苹果。 `Program.cs` ```cs using System; namespace Apples { class Program { static void Main(string[] args) { int baskets = 16; int applesInBasket = 24; int total = baskets * applesInBasket; Console.WriteLine("There are total of {0} apples", total); } } } ``` 在我们的程序中,我们计算了苹果的总量。 我们使用乘法运算。 ```cs int baskets = 16; int applesInBasket = 24; ``` 篮子数和每个篮子中的苹果数是整数值。 ```cs int total = baskets * applesInBasket; ``` 将这些值相乘,我们也得到一个整数。 ```cs $ dotnet run There are total of 384 apples ``` 这是程序的输出。 ### C# 整数符号 可以在 C# 中使用三种不同的表示法指定整数:十进制,十六进制和二进制。 八进制值没有符号。 据我们所知,通常使用十进制数。 十六进制数字以`0x`字符开头,以`0b`二进制文件开头。 `Program.cs` ```cs using System; namespace IntegerNotations { class Program { static void Main(string[] args) { int num1 = 31; int num2 = 0x31; int num3 = 0b1101; Console.WriteLine(num1); Console.WriteLine(num2); Console.WriteLine(num3); } } } ``` 在程序中,我们用三个不同的符号表示三个整数。 ```cs $ dotnet run 31 49 13 ``` 默认符号是十进制。 程序以十进制显示这两个数字。 换句话说,十六进制的`0x31`是十进制的 49。 ### 使用下划线 C# 允许对数字字面值使用下划线字符,以提高值的可读性。 `Program.cs` ```cs using System; namespace UnderscoreLiterals { class Program { static void Main(string[] args) { var num1 = 234_321_000; Console.WriteLine(num1); var num2 = 0b_0110_000_100; Console.WriteLine(num2); } } } ``` 该程序使用带下划线字符的整数字面值来提高值的可读性。 ### 算术溢出 算术溢出是在计算产生的结果的大小大于给定寄存器或存储位置可以存储或表示的结果时发生的条件。 `Program.cs` ```cs using System; namespace OverFlow { class Program { static void Main(string[] args) { byte a = 254; Console.WriteLine(a); a++; Console.WriteLine(a); a++; Console.WriteLine(a); a++; Console.WriteLine(a); } } } ``` 在此示例中,我们尝试分配一个超出数据类型范围的值。 这导致算术溢出。 ```cs $ dotnet run 254 255 0 1 ``` 发生溢出时,变量将重置为数据类型的下限。 (如果是字节类型,则为零。) 使用`checked`关键字,可以在发生溢出时强制执行异常。 `Program.cs` ```cs using System; namespace OverflowChecked { class Program { static void Main(string[] args) { checked { byte a = 254; Console.WriteLine(a); a++; Console.WriteLine(a); a++; Console.WriteLine(a); a++; Console.WriteLine(a); } } } } ``` 在该示例中,语句放置在`checked`块的主体中​​。 ```cs $ dotnet run 254 255 Unhandled Exception: System.OverflowException: Arithmetic operation resulted in an overflow. ... ``` 这次抛出了`System.OverflowException`。 ## C# 浮点数 浮点数表示计算中的实数。 实数测量连续的数量,例如重量,高度或速度。 在 C# 中,我们有三种浮点类型:`float`,`double`和`decimal`。 | C# 别名 | .NET 类型 | 大小 | 精度 | 范围 | | --- | --- | --- | --- | --- | | `float` | `System.Single` | 4 字节 | 7 位数 | `+-1.5 x 10^-45`至`+-3.4 x 10^38` | | `double` | `System.Double` | 8 字节 | 15-16 位数 | `+-5.0 x 10^-324`至`+-1.7 x 10^308` | | `decimal` | `System.Decimal` | 16 字节 | 28-29 位小数 | `+-1.0 x 10^-28`至`+-7.9 x 10^28` | 上表给出了浮点类型的特征。 默认情况下,C# 程序中的实数是双精度的。 要使用其他类型,必须使用后缀。 `float`编号为`F/f`,`decimal`编号为`M/m`。 `Program.cs` ```cs using System; namespace Floats { class Program { static void Main(string[] args) { float n1 = 1.234f; double n2 = 1.234; decimal n3 = 1.234m; Console.WriteLine(n1); Console.WriteLine(n2); Console.WriteLine(n3); Console.WriteLine(n1.GetType()); Console.WriteLine(n2.GetType()); Console.WriteLine(n3.GetType()); } } } ``` 在上面的程序中,我们对浮点数使用三种不同的字面值符号。 ```cs float n1 = 1.234f; ``` `f`后缀用于`float`数字。 ```cs double n2 = 1.234; ``` 如果我们不使用后缀,则为`double`数字。 我们可以选择使用`d`后缀。 ```cs Console.WriteLine(n1.GetType()); ``` `GetType()`方法返回数字的类型。 ```cs $ dotnet run 1.234 1.234 1.234 System.Single System.Double System.Decimal ``` 这是输出。 我们可以使用各种语法来创建浮点值。 `Program.cs` ```cs using System; namespace Notations { class Program { static void Main(string[] args) { float n1 = 1.234f; float n2 = 1.2e-3f; float n3 = (float)1 / 3; Console.WriteLine(n1); Console.WriteLine(n2); Console.WriteLine(n3); } } } ``` 我们有三种创建浮点值的方法。 第一种是使用小数点的“正常”方式。 第二种使用科学计数法。 最后一个是数字运算的结果。 ```cs float n2 = 1.2e-3f; ``` 这是浮点数的科学表示法。 也称为指数表示法,它是一种写数字太大或太小而不能方便地用标准十进制表示法写的方式。 ```cs float n3 = (float) 1 / 3; ``` `(float)`构造称为转换。 默认情况下,除法运算将返回整数。 通过强制转换,我们得到一个浮点数。 ```cs $ dotnet run 1.234 0.0012 0.3333333 ``` 这是上面程序的输出。 `float`和`double`类型不精确。 `Program.cs` ```cs using System; namespace InExact { class Program { static void Main(string[] args) { double n1 = 0.1 + 0.1 + 0.1; double n2 = 1 / 3.0; if (n1 == n2) { Console.WriteLine("Numbers are equal"); } else { Console.WriteLine("Numbers are not equal"); } } } } ``` 比较浮点值时应格外小心。 ```cs $ dotnet run Numbers are not equal ``` 而且数字不相等。 假设一个短跑运动员跑了 1 个小时,跑了 9.87 秒。 他的公里/小时速度是多少? `Program.cs` ```cs using System; namespace Sprinter { class Program { static void Main(string[] args) { float distance = 0.1f; float time = 9.87f / 3600; float speed = distance / time; Console.WriteLine("The average speed of a sprinter is {0} km/h", speed); } } } ``` 在此示例中,必须使用浮点值。 ```cs float distance = 0.1f; ``` 100m 是 0.1 km。 ```cs float time = 9.87f / 3600; ``` 9.87s 是`9.87 / (60 * 60)`h。 ```cs float speed = distance / time; ``` 为了获得速度,我们将距离除以时间。 ```cs $ dotnet run The average speed of a sprinter is 36.47416 km/h ``` This is the output of the program. ## C# 枚举 枚举类型(也称为枚举或枚举)是由一组命名值组成的数据类型。 可以将任何枚举器分配为已声明为具有枚举类型的变量作为值。 枚举使代码更具可读性。 `Program.cs` ```cs using System; namespace Enumerations { enum Days { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } class Program { static void Main(string[] args) { Days day = Days.Monday; if (day == Days.Monday) { Console.WriteLine("It is Monday"); } Console.WriteLine(day); foreach (int i in Enum.GetValues(typeof(Days))) { Console.WriteLine(i); } } } } ``` 在我们的代码示例中,我们为工作日创建一个枚举。 ```cs enum Days { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } ``` 使用`enum`关键字创建枚举。 星期一,星期二,...星期日实际上存储着数字`0..6`。 ```cs Days day = Days.Monday; ``` 我们有一个名为`day`的变量,其类型为`Days`。 它被初始化为星期一。 ```cs if (day == Days.Monday) { Console.WriteLine("It is Monday"); } ``` 与将日变量与某个数字进行比较相比,此代码更具可读性。 ```cs Console.WriteLine(day); ``` 该行将在星期一打印到控制台。 ```cs foreach (int i in Enum.GetValues(typeof(Days))) { Console.WriteLine(i); } ``` 此循环将`0..6`打印到控制台。 我们得到`enum`值的基础类型。 对于计算机,`enum`只是一个数字。 `typeof`是用于获取类型的`System.Type`对象的运算符。 `GetValues()`方法需要它。 此方法返回指定枚举值的数组。 `foreach`关键字逐个元素地遍历数组并将其打印到终端。 我们会进一步进行枚举。 `Program.cs` ```cs using System; using System; namespace Seasons { public enum Seasons : byte { Spring = 1, Summer = 2, Autumn = 3, Winter = 4 } class Program { static void Main(string[] args) { Seasons s1 = Seasons.Spring; Seasons s2 = Seasons.Autumn; Console.WriteLine(s1); Console.WriteLine(s2); } } } ``` 季节可以很容易地用作枚举。 我们可以为`enum`指定基础类型,并且可以为其提供确切的值。 ```cs public enum Seasons : byte { Spring = 1, Summer = 2, Autumn = 3, Winter = 4 } ``` 使用冒号和数据类型,我们指定`enum`的基础类型。 我们还给每个成员一个特定的号码。 ```cs Console.WriteLine(s1); Console.WriteLine(s2); ``` 这两行将`enum`值打印到控制台。 ```cs $ dotnet run Spring Autumn ``` This is the output of the program. ## C# 元组 元组是异类数据值的有序的,不变的列表。 元组是值类型。 元组必须至少包含两个元素。 元组用圆括号`()`定义。 `Program.cs` ```cs using System; namespace Tuples { class Program { static void Main(string[] args) { var words = ("sky", "blue", "rock", "fountain"); Console.WriteLine(words); Console.WriteLine(words.Item1); Console.WriteLine(words.Item2); var words2 = (w1: "forest", w2: "deep", w3: "sea"); Console.WriteLine(words2.w1); Console.WriteLine(words2.w2); Console.WriteLine(words2.w3); } } } ``` 在示例中,我们定义了两个元组。 ```cs var words = ("sky", "blue", "rock", "fountain"); ``` 这是一个未命名的元组定义。 ```cs Console.WriteLine(words); ``` 我们将元组的所有元素打印到控制台。 ```cs Console.WriteLine(words.Item1); Console.WriteLine(words.Item2); ``` 我们打印前两个元素。 我们使用特殊的`Item1`,`Item2`,...属性访问未命名元组的元素。 ```cs var words2 = (w1: "forest", w2: "deep", w3: "sea"); ``` 这是一个命名元组的定义。 ```cs Console.WriteLine(words2.w1); Console.WriteLine(words2.w2); Console.WriteLine(words2.w3); ``` 我们通过元素名称访问元素。 ```cs $ dotnet run (sky, blue, rock, fountain) sky blue forest deep sea ``` This is the output. ## C# 字符串和字符 `string`是代表计算机程序中文本数据的数据类型。 C# 中的字符串是 Unicode 字符序列。 `char`是单个 Unicode 字符。 字符串用双引号引起来。 由于字符串在每种编程语言中都非常重要,因此我们将为它们专门整整一章。 这里我们仅举一个小例子。 `Program.cs` ```cs using System; namespace Strings { class Program { static void Main(string[] args) { string word = "ZetCode"; char c = word[0]; Console.WriteLine(c); } } } ``` 程序将`'Z'`字符打印到终端。 ```cs string word = "ZetCode"; ``` 在这里,我们创建一个字符串变量,并为其分配`"ZetCode"`值。 ```cs char c = word[0]; ``` `string`是 Unicode 字符数组。 我们可以使用数组访问符号从字符串中获取特定字符。 方括号内的数字是字符数组的索引。 索引从零开始计数。 这意味着第一个字符的索引为 0。 ```cs $ dotnet run Z ``` 该程序将`"ZetCode"`字符串的第一个字符打印到控制台。 ## C# 数组 数组是处理元素集合的复杂数据类型。 每个元素都可以通过索引访问。 数组的所有元素必须具有相同的数据类型。 我们将整章专门介绍数组。 这里我们仅显示一个小例子。 `Program.cs` ```cs using System; namespace ArrayEx { class Program { static void Main(string[] args) { int[] numbers = new int[5]; numbers[0] = 3; numbers[1] = 2; numbers[2] = 1; numbers[3] = 5; numbers[4] = 6; int len = numbers.Length; for (int i = 0; i < len; i++) { Console.WriteLine(numbers[i]); } } } } ``` 在此示例中,我们声明一个数组,用数据填充它,然后将数组的内容打印到控制台。 ```cs int[] numbers = new int[5]; ``` 我们声明一个整数数组,该数组最多可以存储五个整数。 因此,我们有五个元素组成的数组,索引为`0..4`。 ```cs numbers[0] = 3; numbers[1] = 2; numbers[2] = 1; numbers[3] = 5; numbers[4] = 6; ``` 在这里,我们为创建的数组分配值。 我们可以通过数组访问符号访问数组的元素。 它由数组名称和方括号组成。 在方括号内,我们指定所需元素的索引。 ```cs int len = numbers.Length; ``` 每个数组都有一个`Length`属性,该属性返回数组中的元素数。 ```cs for (int i=0; i<len; i++) { Console.WriteLine(numbers[i]); } ``` 我们遍历数组并将数据打印到控制台。 ## C# `DateTime` `DateTime`是一种值类型。 它代表时间的瞬间,通常表示为日期和时间。 `Program.cs` ```cs using System; namespace DateTimeEx { class Program { static void Main(string[] args) { DateTime now = DateTime.Now; System.Console.WriteLine(now); System.Console.WriteLine(now.ToShortDateString()); System.Console.WriteLine(now.ToShortTimeString()); } } } ``` 我们以三种不同的格式显示今天的日期:日期&时间,日期和时间。 ```cs DateTime now = DateTime.Now; ``` 获取一个`DateTime`对象,该对象设置为此计算机上的当前日期和时间,表示为本地时间。 ```cs System.Console.WriteLine(now); ``` 此行以完整格式打印日期。 ```cs System.Console.WriteLine(now.ToShortDateString()); System.Console.WriteLine(now.ToShortTimeString()); ``` `ToShortDateString()`返回短日期字符串格式,`ToShortTimeString()`返回短时间字符串格式。 ```cs $ dotnet run 12/5/2018 8:09:56 PM 12/5/2018 8:09 PM ``` 我们看到示例的输出。 ## C# 类型转换 我们经常一次处理多种数据类型。 将一种数据类型转换为另一种数据类型是编程中的常见工作。 类型转换或类型转换是指将一种数据类型的实体更改为另一种。 有两种转换类型:隐式转换和显式转换。 隐式类型转换,也称为强制转换,是编译器自动进行的类型转换。 `Program.cs` ```cs using System; namespace ImplicitTypeConversion { class Program { static void Main(string[] args) { int val1 = 0; byte val2 = 15; val1 = val2; Console.WriteLine(val1.GetType()); Console.WriteLine(val2.GetType()); Console.WriteLine(12 + 12.5); Console.WriteLine("12" + 12); } } } ``` 在此示例中,我们有几个隐式转换。 ```cs val1 = val2; ``` 在这里,我们使用两种不同的类型:`int`和`byte`。 我们将`byte`值分配给`int`值。 这是一个扩大的操作。 `int`值有四个字节。 字节值只有一个字节。 允许扩展转换。 如果我们想将`int`分配给`byte`,这将是缩短转换。 C# 编译器不允许隐式缩短转换。 这是因为在隐式缩短转换中,我们可能会无意间降低精度。 我们可以缩短转换时间,但是我们必须将其告知编译器。 我们知道自己在做什么。 可以通过显式转换来完成。 ```cs Console.WriteLine(12 + 12.5); ``` 我们添加两个值:一个整数和一个浮点值。 结果是浮点值。 这是一个不断扩大的隐式转换。 ```cs Console.WriteLine("12" + 12); ``` 结果为 1212。​​将整数转换为字符串,然后将两个字符串连接在一起。 接下来,我们将展示一些在 C# 中的显式转换。 `Program.cs` ```cs using System; namespace ExplicitTypeConversion { class Program { static void Main(string[] args) { double b = 13.5; float a = (float) b; float c = (int) a; Console.WriteLine(a); Console.WriteLine(b); Console.WriteLine(c); } } } ``` 我们有三个值。 我们使用这些值进行一些显式转换。 ```cs float a = (float) b; ``` 我们将`double`值转换为`float`值。 通过在两个圆括号之间指定所需的类型来进行显式转换。 在这种情况下,不会损失任何精度。 数字 13.5 可以安全地分配给这两种类型。 ```cs float c = (int) a; ``` 我们将`float`值转换为`int`值。 在此语句中,我们失去了一些精度:13.5 变为 13。 ```cs $ dotnet run 13.5 13.5 13 ``` 我们看到了程序的输出。 ## C# 可空类型 不能为值类型分配`null`字面值,可以给引用类型分配值。 使用数据库的应用处理空值。 因此,C# 语言中引入了特殊的可空类型。 可空类型是`System.Nullable<T>`结构的实例。 `Program.cs` ```cs using System; class NullableType { static void Main() { Nullable<bool> male = null; int? age = null; Console.WriteLine(male.HasValue); Console.WriteLine(age.HasValue); } } ``` 一个简单的示例,演示可空类型。 ```cs Nullable<bool> male = null; int? age = null; ``` 有两种方法可以声明可为空的类型。 在`Nullable<T>`通用结构中,在尖括号之间指定了类型,或者我们可以在类型后使用问号。 后者实际上是第一种表示法的简写。 ```cs $ dotnet run False False ``` 这是示例的输出。 ## C# 转换&解析方法 有两种用于转换值的方法。 `Program.cs` ```cs using System; namespace ConvertEx { class Program { static void Main(string[] args) { Console.WriteLine(Convert.ToBoolean(0.3)); Console.WriteLine(Convert.ToBoolean(3)); Console.WriteLine(Convert.ToBoolean(0)); Console.WriteLine(Convert.ToBoolean(-1)); Console.WriteLine(Convert.ToInt32("452")); Console.WriteLine(Convert.ToInt32(34.5)); } } } ``` `Convert`类具有许多用于转换值的方法。 我们使用其中两个。 ```cs Console.WriteLine(Convert.ToBoolean(0.3)); ``` 我们将`double`值转换为`bool`值。 ```cs Console.WriteLine(Convert.ToInt32("452")); ``` 在这里,我们将`string`转换为`int`。 ```cs $ dotnet run True True False True 452 34 ``` This is the output. `Program.cs` ```cs using System; namespace ParseEx { class Program { static void Main(string[] args) { Console.WriteLine(Int32.Parse("34")); Console.WriteLine(Int32.Parse("-34")); Console.WriteLine(Int32.Parse("+34")); } } } ``` 将字符串转换为整数是非常常见的任务。 当我们从数据库或 GUI 组件中获取值时,我们通常会进行此类转换。 ```cs Console.WriteLine(Int32.Parse("34")); ``` 我们使用`Int32`类的`Parse()`方法将`string`转换为`int`值。 ```cs $ dotnet run 34 -34 34 ``` This is the output. 在 C# 教程的这一部分中,我们介绍了数据类型及其转换。