C# - 数据类型
C# - 数据类型
Section titled “C# - 数据类型”在 C# 中,**数据类型(data type)指定了变量可以保存的数据种类,例如数字、文本或真/假值。作为一种静态类型(statically-typed)且类型安全(type-safe)**的语言,C# 要求你在使用变量之前声明其类型。这有助于在编译时捕获错误,从而产生更健壮、更可靠的软件。
C# 数据类型大致分为两种主要类型:值类型(Value Types)和引用类型(Reference Types)。
1. 值类型
Section titled “1. 值类型”值类型直接包含其数据,并且通常存储在**栈(stack)**上,这是用于短期数据的快速内存区域。当你将一个值类型变量赋给另一个变量时,会创建值的副本。
常见的值类型包括:
- 整型:
int、long、byte、short(用于整数)。 - 浮点型:
double、float、decimal(用于带小数的数字)。 - 其他类型:
bool(真/假)、char(单个字符)、enum(一组命名常量)和struct(用户定义的值类型)。
| Type | Size (Bytes) | 最佳应用场景 |
|---|---|---|
| int | 4 | 通用整数(例如:年龄、计数) |
| long | 8 | 非常大的整数(例如:数据库 ID) |
| double | 8 | 通用浮点数(例如:科学计算) |
| decimal | 16 | 高精度财务计算(例如:货币) |
int age = 30;double pi = 3.14159;decimal price = 19.99m; // `decimal` 类型的后缀 'm'long population = 8_000_000_000L; // `long` 类型的后缀 'L',`_` 用于提高可读性布尔和字符类型
Section titled “布尔和字符类型”bool isComplete = true;char grade = 'A';2. 引用类型
Section titled “2. 引用类型”引用类型不直接存储实际数据。相反,它们存储一个引用(或内存地址)指向数据,而数据本身位于**堆(heap)**上,这是一个用于长期对象的内存区域。当你将一个引用类型变量赋给另一个变量时,只复制引用,而不是对象本身。两个变量都将指向同一个对象。
常见的引用类型包括:
string:字符序列。object:.NET 中所有类型的最终基类。- 数组(Arrays):相同类型元素的集合。
- 类(Classes)、接口(Interfaces)、委托(Delegates)、记录(Records):用户定义的引用类型。
// s1 持有堆上一个对象的引用。string s1 = "Hello";
// s2 现在持有该引用的副本,指向同一个对象。string s2 = s1;
// 注意:`string` 是一个特例;它是不可变的。看似修改 `string` 的操作// 实际上是创建了一个新的 `string` 对象。
// 一个标准的类示例var person1 = new Person { Name = "John" };var person2 = person1; // 两者都引用同一个 `Person` 对象person2.Name = "Jane";
Console.WriteLine(person1.Name); // 输出:Jane3. var 关键字:隐式类型
Section titled “3. var 关键字:隐式类型”var 关键字允许编译器从变量的初始化值推断其类型。这可以通过减少冗余使代码更具可读性。
重要提示: var 不意味着变量是动态类型化(dynamic typed)的(像在 JavaScript 中那样)。类型仍然在编译时确定,之后不能更改。它只是语法糖。
var message = "This is a string"; // 编译器推断为 `string`var count = 100; // 编译器推断为 `int`var prices = new List<decimal>(); // 编译器推断为 `List<decimal>`4. 可空类型
Section titled “4. 可空类型”默认情况下,引用类型可以为 null,而值类型不能。C# 提供了安全处理可空性(nullability)的功能。
- 可空值类型(Nullable Value Types): 要使值类型可空,请在其类型声明后附加一个
?。例如:int? age = null;。 - 可空引用类型(Nullable Reference Types - NRTs): C# 的一项现代功能(在新项目中默认启用),可帮助你避免可怕的
NullReferenceException。如果你尝试在未先检查的情况下使用可能为null的引用类型,编译器会发出警告。
// 在项目文件中启用 NRTs:<Nullable>enable</Nullable>
string nonNullableName = "World"; // 不能为 `null`string? nullableName = null; // 可以为 `null`
Console.WriteLine($"Hello, {nonNullableName.ToUpper()}"); // 安全
// 编译器警告:nullableName 在这里可能为 `null`。// Console.WriteLine($"Hello, {nullableName.ToUpper()}");
// 正确的检查方式:if (nullableName != null){ Console.WriteLine($"Hello, {nullableName.ToUpper()}");}5. 类型转换
Section titled “5. 类型转换”将数据从一种类型转换为另一种类型是一项常见的任务。
- 隐式转换(安全): 当不会丢失数据时自动发生。
int到double是安全的。 - 显式转换(强制类型转换): 当数据可能丢失时需要。你必须使用强制类型转换运算符
(type)。double到int是显式转换,因为小数部分会丢失。 - 辅助方法(最安全):
Convert类和TryParse方法是处理来自外部源(如用户输入或文件)转换的最佳方式。
// 1. 隐式转换int myInt = 10;double myDouble = myInt; // 安全,无数据丢失
// 2. 显式转换(强制类型转换)double anotherDouble = 9.78;int anotherInt = (int)anotherDouble; // 显式强制类型转换,结果为 9
// 3. 辅助方法(最佳实践)string userInput = "123";if (int.TryParse(userInput, out int parsedValue)){ Console.WriteLine($"成功解析为: {parsedValue}");}else{ Console.WriteLine("无效的数字格式。");}6. 高级:指针类型
Section titled “6. 高级:指针类型”指针类型是从 C/C++ 继承的特性。它们存储变量的内存地址。这是一个高级功能,在典型的 C# 应用程序代码中很少使用。 它主要用于对性能要求极高的场景或与非托管代码(如 C++ 库)进行互操作。
警告: 使用指针的代码必须用 unsafe 关键字标记,并且可能需要特定的编译器设置(在 .csproj 文件中添加 <AllowUnsafeBlocks>true</AllowUnsafeBlocks>)。请务必谨慎使用。
public class UnsafeExample{ public static unsafe void Main() { int number = 20;
// `&` 运算符获取变量的内存地址 int* pointerToNumber = &number;
Console.WriteLine($"Value of number: {number}"); Console.WriteLine($"Address of number: {(long)pointerToNumber}"); Console.WriteLine($"Value via pointer: {*pointerToNumber}");
// 使用指针修改值 *pointerToNumber = 30; Console.WriteLine($"New value of number: {number}"); }}