C# 数据类型(千字长文)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

在编程的世界中,数据类型是构建程序的基石。无论是存储用户输入的文本、计算数学公式,还是处理图像或音频文件,数据类型决定了代码如何高效、安全地管理信息。对于 C# 开发者而言,理解数据类型的核心特性与使用场景,是编写健壮且高性能代码的关键。本文将从基础到进阶,系统讲解 C# 中的数据类型体系,并通过案例演示其实际应用。


一、数据类型的分类与基础概念

C# 是一种静态类型语言,这意味着变量的数据类型在编译时即被确定。数据类型决定了变量的存储空间、取值范围以及可执行的操作。根据内存管理方式和存储特性,C# 数据类型可分为两大类:值类型(Value Types)引用类型(Reference Types)

1.1 值类型:直接存储数据

值类型直接将数据存储在内存的栈(Stack)中,具有以下特点:

  • 独立性:每个变量拥有独立的内存空间,修改一个变量不会影响其他变量。
  • 轻量高效:由于存储在栈中,内存分配和释放速度快,适合存储简单数据。

常见值类型包括:
| 类型 | 描述 | 存储空间 | 取值范围示例 |
|-----------|-----------------------------|----------|---------------------------|
| int | 整数类型 | 4 字节 | -2,147,483,648 到 2,147,483,647 |
| float | 单精度浮点数 | 4 字节 | 约 ±1.5×10^-45 到 ±3.4×10^38 |
| char | 字符类型 | 2 字节 | Unicode 字符(如 'A', '€') |
| bool | 布尔类型 | 1 字节 | truefalse |

示例代码

int age = 25;          // 整数类型  
float price = 9.99f;   // 浮点类型(注意后缀 f)  
char initial = 'J';    // 字符类型  
bool isStudent = true; // 布尔类型  

1.2 引用类型:间接访问数据

引用类型的数据存储在堆(Heap)中,变量实际上保存的是指向堆内存的地址。其特点包括:

  • 共享性:多个变量可以引用同一块内存空间,修改数据会影响所有引用变量。
  • 灵活性:适合存储复杂对象(如类、数组、接口等),但访问速度略慢于值类型。

常见引用类型包括:

  • 类(Class):如 System.String、用户自定义的 Person 类。
  • 接口(Interface):定义行为规范的抽象类型。
  • 数组(Array):如 int[] numbers
  • 委托(Delegate):用于封装方法引用。

示例代码

string name = "Alice";       // 字符串类型(引用类型)  
List<int> numbers = new List<int>(); // 集合类型(基于类)  

二、值类型与引用类型的对比

理解两者的区别对编程至关重要。以下通过比喻和代码示例帮助读者直观掌握:

2.1 值类型的“独立性”比喻

假设值类型是一个装满糖果的玻璃罐:

  • 每个变量(罐子)独立存在,你从罐A中拿走糖果,罐B中的糖果数量不变。
int a = 10;  
int b = a; // 复制罐A中的糖果到罐B  
a = 20;    // 只影响罐A,罐B仍为 10  

2.2 引用类型的“共享性”比喻

引用类型更像是指向同一张地图的多个指南针:

  • 变更地图内容会影响所有指南针指向的区域。
Person person1 = new Person { Name = "Bob" };  
Person person2 = person1; // 两个变量指向同一块内存  
person1.Name = "Charlie"; // person2.Name 同步变为 "Charlie"  

三、类型转换与安全性

C# 的类型系统通过显式隐式转换机制,确保代码的安全性。

3.1 隐式转换:自动且安全

当转换不会导致数据丢失时,编译器自动执行隐式转换。例如:

short small = 123;  
int big = small; // 小范围到大范围,自动转换  

3.2 显式转换:强制且需谨慎

当转换可能丢失数据时,必须通过 () 语法显式执行。例如:

int number = 255;  
byte smallNumber = (byte)number; // 强制转换为 0-255,结果为 255  

3.3 类型转换的陷阱

尝试将 string 转换为 int 时,需使用 int.Parse()int.TryParse(),否则会引发异常:

string input = "123";  
int value = int.Parse(input); // 成功  
string invalidInput = "ABC";  
int invalidValue = int.Parse(invalidInput); // 抛出 FormatException  

四、结构体(Struct)与枚举(Enum)

4.1 结构体:轻量级值类型

结构体(struct)是用户自定义的值类型,适合存储轻量、不频繁改变的数据。例如:

public struct Point {  
    public int X;  
    public int Y;  
}  

Point origin = new Point { X = 0, Y = 0 };  

4.2 枚举(Enum):命名常量集合

枚举为一组命名的整数常量提供类型安全的表示:

public enum Weekday {  
    Monday, Tuesday, Wednesday,  
    Thursday, Friday, Saturday, Sunday  
}  

Weekday today = Weekday.Monday;  

五、实际案例:温度转换器

通过一个完整案例,演示数据类型的选择与应用:

5.1 需求分析

构建一个将摄氏温度转换为华氏温度的工具,需满足以下条件:

  • 输入为浮点数(如 36.5°C)。
  • 输出保留两位小数。
  • 提供类型安全的单位标识(如 CelsiusFahrenheit)。

5.2 代码实现

public enum TemperatureUnit { Celsius, Fahrenheit }  

public struct Temperature {  
    public float Value { get; }  
    public TemperatureUnit Unit { get; }  

    public Temperature(float value, TemperatureUnit unit) {  
        Value = value;  
        Unit = unit;  
    }  

    public float ToCelsius() {  
        if (Unit == TemperatureUnit.Celsius) return Value;  
        return (Value - 32) * 5 / 9;  
    }  

    public float ToFahrenheit() {  
        if (Unit == TemperatureUnit.Fahrenheit) return Value;  
        return Value * 9 / 5 + 32;  
    }  
}  

class Program {  
    static void Main() {  
        Temperature temp = new Temperature(100, TemperatureUnit.Celsius);  
        float fahrenheit = temp.ToFahrenheit();  
        Console.WriteLine($"{temp.Value}°C = {fahrenheit:F2}°F");  
    }  
}  

5.3 代码解析

  • 枚举 TemperatureUnit:确保单位类型安全,避免拼写错误。
  • 结构体 Temperature:作为值类型,每次传递时复制数据,避免意外修改。
  • 方法 ToCelsius()ToFahrenheit():通过浮点运算实现精准转换。

六、高级主题:类型推断与泛型

6.1 类型推断(var 关键字)

C# 允许使用 var 关键字让编译器自动推断变量类型:

var message = "Hello, C#!"; // 推断为 string 类型  
var count = 42;             // 推断为 int 类型  

注意:var 必须在初始化时赋值,且类型明确。

6.2 泛型:类型安全的复用

泛型(Generics)允许创建可复用的代码模板,同时确保类型安全:

public class Box<T> {  
    public T Content { get; set; }  
}  

Box<int> numberBox = new Box<int>();  
numberBox.Content = 100; // 正确  
numberBox.Content = "ABC"; // 编译错误  

结论

C# 数据类型体系的深度理解,是开发者从“能写代码”进阶到“写出优质代码”的关键。通过本文的讲解,读者应能掌握以下核心要点:

  1. 值类型与引用类型的内存管理差异。
  2. 类型转换的安全性原则与常见陷阱。
  3. 结构体、枚举、泛型等高级特性的应用场景。
  4. 通过案例实践巩固理论知识。

未来学习中,建议进一步探索 Nullable<T>dynamic 类型以及 .NET 的类型系统底层实现。掌握这些内容,将使你能够更自信地应对复杂项目的开发挑战。


(全文约 1,800 字)

最新发布