首先你要知道C#的数据类型分为两大类:值类型(Value Types) 和 引用类型(Reference Types)。
1. 值类型(Value Types)
值类型直接存储数据值,存储在栈内存中,具有高性能特点。
1.1 简单类型(内置数值类型)
这些类型是C#语言的内置类型,用于存储数值数据。
整数类型
int(默认)(常用)、byte/short/long
int age = 18; // 存年龄
int appleCount = 5 + 3; // 计算总数
Console.Write(appleCount); // 输出8
实数类型
即其他语言中的浮点型,为带小数的类型。
float
, double
(默认浮点类型)decimal
(高精度财务计算)
double price = 3.5; // 存价格
double total = price * 10 * 0.9; // 计算9折总价
Console.Write(total); // 输出31.5
decimal salary = 12345.6789m; // 后缀'm'不可省略
字符类型
char
:表示单个字符,用单引号括起来。常用于处理文本中的单个字符,如字符串中的某个字符提取、字符比较等。
char letter = 'A'; // 占2字节
Console.WriteLine(letter); // 输出:A
布尔型(bool)
只有 true
和 false
两个值,用于表示逻辑判断结果,在条件语句(如 if - else
)和循环控制(如 while
循环的条件判断)中广泛使用
bool hasRain = true; // true=是,false=否
if (hasRain)
{
Console.Write("宝儿,今天下雨 ,出门记得带伞哦");
}
1. 2复杂类型
枚举类型(Enumeration Types)
- 通过
enum
关键字定义,用于将一组相关的命名常量组合在一起,默认基础类型为int
。。常用于表示一组固定的选项,让代码更具可读性和可维护性,比如在表示订单状态(未支付、已支付、已发货等)时就可以使用枚举。 -
// 定义一个枚举类型 DayOfWeek,用于表示一周中的每一天 // 枚举是一种值类型,它为一组相关的命名常量提供了一种便捷的方式 enum DayOfWeek { // 定义枚举成员 Monday,表示星期一,默认情况下,第一个枚举成员的值为 0 Monday, // 定义枚举成员 Tuesday,表示星期二,其值默认比前一个成员(Monday)大 1,即值为 1 Tuesday, // 定义枚举成员 Wednesday,表示星期三,值为 2 Wednesday, // 定义枚举成员 Thursday,表示星期四,值为 3 Thursday, // 定义枚举成员 Friday,表示星期五,值为 4 Friday, // 定义枚举成员 Saturday,表示星期六,值为 5 Saturday, // 定义枚举成员 Sunday,表示星期日,值为 6 Sunday } class Program { static void Main() { // 声明一个 DayOfWeek 类型的变量 today,并将其初始化为 DayOfWeek.Monday DayOfWeek today = DayOfWeek.Monday; // 使用 Console.WriteLine 方法将变量 today 的值输出到控制台 // 由于 DayOfWeek 类型重写了 ToString 方法,所以会输出枚举成员的名称 "Monday" Console.WriteLine(today); } }
结构体类型(Structures)
-
使用
struct
关键字定义,是一种值类型,可以将不同类型的数据组合在一起。 -
// 定义一个名为Point的结构体,结构体是一种值类型, // 用于将相关的数据成员组合在一起,这里用于表示二维平面上的点 struct Point { // 定义一个公共字段X,用于表示点在x轴上的坐标,类型为整数 public int X; // 定义一个公共字段Y,用于表示点在y轴上的坐标,类型为整数 public int Y; // 定义一个构造函数,该构造函数用于初始化Point结构体的实例 // 参数x表示点在x轴上的初始坐标值 // 参数y表示点在y轴上的初始坐标值 public Point(int x, int y) { // 将传入的参数x的值赋给字段X,从而设置点在x轴上的坐标 X = x; // 将传入的参数y的值赋给字段Y,从而设置点在y轴上的坐标 Y = y; } } class Program { static void Main() { // 创建一个Point结构体的实例p,通过构造函数传入x坐标值10和y坐标值20 Point p = new Point(10, 20); // 使用Console.WriteLine方法输出点的坐标信息。 // 这里使用了字符串插值,将p.X和p.Y的值插入到字符串中相应的位置 // 最终输出的字符串形式为“点的坐标是 (10, 20)” Console.WriteLine($"点的坐标是 ({p.X}, {p.Y})"); } }
2.引用类型
-
类类型
- 使用
class
关键字定义,是面向对象编程的核心。类可以包含数据成员(字段、属性)和函数成员(方法、构造函数等)。 // 定义一个名为Person的类,类是一种引用类型,用于封装相关的数据和行为 class Person { // 声明一个私有字段name,用于存储人的名字,类型为字符串 // 私有字段只能在类的内部访问,提供了一定的数据封装性 private string name; // 定义一个公共属性Age,用于获取和设置人的年龄,类型为整数 // 这里使用了自动实现的属性,C#编译器会自动生成一个用于存储年龄值的幕后字段 public int Age { get; set; } // 定义构造函数,用于创建Person类的实例并初始化其属性 // 构造函数的名称与类名相同 // 参数name表示人的名字 // 参数age表示人的年龄 public Person(string name, int age) { // 将传入的name参数赋值给类的私有字段name this.name = name; // 使用属性Age来设置人的年龄,这样会调用Age属性的set访问器 Age = age; } // 定义一个公共方法SayHello,用于让Person实例输出自我介绍的信息 public void SayHello() { // 使用Console.WriteLine方法在控制台输出自我介绍的字符串 // 这里使用了字符串插值,将name字段和Age属性的值插入到字符串中相应的位置 Console.WriteLine($"Hello, my name is {name} and I'm {Age} years old."); } }
字符串类型
string
用于表示文本数据,是一个引用类型,用双引号括起来。C# 的字符串是不可变的,即一旦创建,其内容不能被修改。当对字符串进行操作时,实际上是创建了一个新的字符串对象。-
string name = "张三"; Console.Write("欢迎" + name); // 输出:欢迎张三
委托类型
- 是一种特殊的引用类型,用于表示对方法的引用。可以将方法作为参数传递给其他方法,实现回调机制。
-
// 定义一个委托类型 PrintMessageDelegate,它表示一个方法的签名。 // 该委托指向的方法没有返回值(void),并且接受一个字符串类型的参数(string message)。 // 任何符合此签名的方法都可以赋值给这种委托类型的变量。 delegate void PrintMessageDelegate(string message); class Program { // 定义一个静态方法 PrintMessage,该方法接受一个字符串参数 message, // 并将这个字符串输出到控制台。 static void PrintMessage(string message) { Console.WriteLine(message); } static void Main() { // 创建一个 PrintMessageDelegate 类型的委托实例 printDelegate, // 并将其初始化为指向 PrintMessage 方法。这意味着 printDelegate 现在可以像调用 PrintMessage 方法一样被调用。 PrintMessageDelegate printDelegate = PrintMessage; // 通过委托实例 printDelegate 调用它所指向的方法(即 PrintMessage 方法), // 并传递字符串 "Hello, delegate!" 作为参数。这会导致 PrintMessage 方法执行,输出 "Hello, delegate!" 到控制台。 printDelegate("Hello, delegate!"); } }
-
数组类型
- 可以存储多个相同类型的数据元素。数组在处理批量数据时非常有用,比如存储学生成绩、图像像素矩阵等。
-
int[] numbers = new int[] { 1, 2, 3, 4, 5 }; Console.WriteLine(numbers[2]); // 输出:3
接口类型
- 使用
interface
关键字定义,它只包含方法、属性等的签名,不包含实现。类或结构体可以实现接口,允许多个不相关的类型实现相同的行为。 -
// 定义一个接口 IPrintable。接口定义了一组方法签名,但不包含方法的实现。 // 任何实现该接口的类都必须提供这些方法的具体实现。 interface IPrintable { // 定义一个抽象方法 Print,该方法没有参数且返回值类型为 void。 // 实现 IPrintable 接口的类必须实现这个 Print 方法。 void Print(); } // 定义一个类 Book,它实现了 IPrintable 接口。 // 这意味着 Book 类必须提供 IPrintable 接口中定义的所有方法的具体实现。 class Book : IPrintable { // 实现 IPrintable 接口中的 Print 方法。 // 当调用 Book 类实例的 Print 方法时,会在控制台输出 "This is a book."。 public void Print() { Console.WriteLine("This is a book."); } } // 定义一个类 Magazine,它同样实现了 IPrintable 接口。 // 所以 Magazine 类也需要提供 Print 方法的具体实现。 class Magazine : IPrintable { // 实现 IPrintable 接口中的 Print 方法。 // 当调用 Magazine 类实例的 Print 方法时,会在控制台输出 "This is a magazine."。 public void Print() { Console.WriteLine("This is a magazine."); } }
3.指针类型(不安全代码中使用)
在 C# 中,指针类型允许直接操作内存地址,这在一些需要高性能和底层操作的场景中有用,但使用指针会使代码变得不安全,需要在
unsafe
上下文中使用。指针类型常用于与非托管代码交互、编写高性能算法等,但要谨慎使用,因为错误的指针操作可能导致内存泄漏和程序崩溃。// 使用 unsafe 关键字开启不安全代码块,在这个代码块内可以使用指针相关的操作 unsafe { // 声明并初始化一个整型变量 number,值为 10 int number = 10; // 声明一个整型指针 pointer,并将其指向变量 number 的内存地址。 // & 符号用于获取变量的内存地址 int* pointer = &number; // 通过解引用指针 *pointer,获取指针所指向的内存地址中的值,并将其输出到控制台 Console.WriteLine(*pointer); } //注意事项: 要编译包含不安全代码的 C# 程序,需要在项目属性中启用 “允许不安全代码” 选项。在 Visual Studio 中,可以在项目属性的 “生成” 选项卡中找到该设置。 直接操作指针可能会导致内存安全问题,如访问未分配的内存、内存泄漏等,使用时需格外小心。