跳到主要内容

C# 数据类型

本章将详细介绍 C# 中的数据类型,包括值类型、引用类型以及它们的内存管理。

值类型与引用类型

基本概念

类型特点示例
值类型直接存储数据,存储在栈上int, double, struct
引用类型存储数据的引用(地址),存储在堆上class, string, array
值类型内存布局:
┌─────────────┐
│ int │ 直接存储值 25
│ 25 │
└─────────────┘

引用类型内存布局:
┌─────────────┐ ┌─────────────┐
│ string │ │ │
│ (引用) ────┼─────▶│ "Hello" │
└─────────────┘ │ (堆内存) │
└─────────────┘

值类型

整数类型

// 有符号整数
sbyte num1 = -128; // 8位: -128 ~ 127
short num2 = -30000; // 16位: -32768 ~ 32767
int num3 = 1000; // 32位: -2147483648 ~ 2147483647
long num4 = 1000000L; // 64位: -9223372036854775808 ~ 9223372036854775807

// 无符号整数
byte num5 = 255; // 8位: 0 ~ 255
ushort num6 = 60000; // 16位: 0 ~ 65535
uint num7 = 1000U; // 32位: 0 ~ 4294967295
ulong num8 = 1000000UL; // 64位: 0 ~ 18446744073709551615

常用整数类型选择

  • 一般使用 int(32位,性能好)
  • 大数字使用 long
  • 文件读写、网络传输使用 int/long

浮点类型

// 单精度浮点数
float f1 = 3.14f; // 32位,精度约7位

// 双精度浮点数(默认)
double d1 = 3.14; // 64位,精度约15位

// 十进制(高精度)
decimal d2 = 3.14m; // 128位,精度约28位,适合金融计算

注意

// 浮点数比较
double a = 0.1 + 0.2;
Console.WriteLine(a == 0.3); // False!精度问题

// 正确做法
Console.WriteLine(Math.Abs(a - 0.3) < 0.0001); // 使用容差比较

布尔类型

bool isActive = true;
bool isDeleted = false;

// 布尔表达式
int age = 20;
bool isAdult = age >= 18; // true

字符类型

char c = 'A';           // 单个字符
char chinese = '中'; // Unicode 字符
char digit = '5';

// 转义字符
char tab = '\t'; // 制表符
char newline = '\n'; // 换行符

// Unicode
char heart = '\u2764'; // ♥

结构体(struct)

// 定义结构体
struct Point
{
public int X;
public int Y;

public Point(int x, int y)
{
X = x;
Y = y;
}
}

// 使用结构体
Point p = new Point(10, 20);
Console.WriteLine($"({p.X}, {p.Y})");

// 也可以直接初始化
Point p2 = new Point { X = 5, Y = 10 };

枚举(enum)

// 定义枚举
enum Level
{
Low, // 默认从 0 开始
Medium, // 1
High // 2
}

// 指定值
enum Status
{
Pending = 0,
Running = 1,
Success = 2,
Failed = 3
}

// 使用枚举
Level level = Level.High;
Console.WriteLine(level); // 输出: High
Console.WriteLine((int)level); // 输出: 2

引用类型

类(class)

class Person
{
public string Name;
public int Age;
}

// 创建对象
Person p = new Person();
p.Name = "张三";
p.Age = 25;

接口(interface)

interface IDisposable
{
void Dispose();
}

数组(array)

int[] numbers = { 1, 2, 3, 4, 5 };
string[] names = new string[3];

字符串(string)

string s1 = "Hello";           // 字符串字面量
string s2 = new string('A', 5); // "AAAAA"
string s3 = null; // 空引用
string s4 = string.Empty; // 空字符串

委托(delegate)

delegate int Calculate(int a, int b);

动态类型(dynamic)

dynamic d = 10;
d = "Hello"; // 运行时才确定类型
Console.WriteLine(d.Length); // 编译时不检查,运行时检查

可空类型

可空值类型

// 语法1:使用 ?
int? nullableInt = null;
bool? nullableBool = null;

// 语法2:使用 Nullable<T>
Nullable<int> nullableInt2 = null;

可空类型的处理

int? num = null;

// 方法1:使用 HasValue 判断
if (num.HasValue)
{
Console.WriteLine(num.Value);
}
else
{
Console.WriteLine("没有值");
}

// 方法2:使用 ?? 运算符(null 合并)
int result = num ?? 0; // 如果 num 为 null,使用默认值 0

// 方法3:使用 ?. 空条件运算符
int? length = num?.ToString()?.Length;

类型转换

隐式转换

// 小类型转大类型(自动)
int i = 100;
long l = i; // int → long
double d = i; // int → double

// 字符串转字符串(无意义但可行)
string s = "hello";
object o = s; // 引用类型隐式转

显式转换

// 强制转换(可能丢失数据)
double d = 123.456;
int i = (int)d; // 123,丢失小数部分

// 使用 Convert 类
int i1 = Convert.ToInt32("123");
double d1 = Convert.ToDouble("3.14");
bool b1 = Convert.ToBoolean(1); // true

// Parse 方法
int i2 = int.Parse("456");
double d2 = double.Parse("3.14");

// TryParse(安全转换)
if (int.TryParse("abc", out int result))
{
Console.WriteLine(result);
}
else
{
Console.WriteLine("转换失败");
}

as 和 is 运算符

object obj = "Hello";

// is:类型检查
if (obj is string)
{
string s = (string)obj;
Console.WriteLine(s.Length);
}

// is:模式匹配(C# 7+)
if (obj is string s)
{
Console.WriteLine(s.Length); // 直接使用 s
}

// as:安全转换(转换失败返回 null)
string s2 = obj as string;
if (s2 != null)
{
Console.WriteLine(s2.Length);
}

默认值

类型默认值
数值类型0
boolfalse
char'\0'
引用类型null
可空类型null
int i = default;        // 0
bool b = default; // false
string s = default; // null

类型信息

获取类型信息

int num = 100;
Type type = num.GetType(); // System.Int32
Console.WriteLine(type.Name); // Int32

// 使用 typeof
Type t = typeof(int);
Console.WriteLine(t.Name); // Int32

记录类型(C# 9+)

// 简单记录
record Person(string Name, int Age);

// 使用
var p = new Person("张三", 25);
var p2 = p with { Age = 26 }; // 创建副本,修改 Age

// 值相等
var p3 = new Person("张三", 25);
Console.WriteLine(p == p3); // True(内容相同)

小结

  1. 值类型:直接存储值,包括整数、浮点、布尔、字符、结构、枚举
  2. 引用类型:存储引用,包括类、接口、数组、委托、字符串
  3. 可空类型:使用 ?Nullable<T> 表示可为空
  4. 类型转换:隐式转换、显式转换、as/is 运算符
  5. 记录类型:C# 9 引入的引用类型,默认值相等比较

练习

  1. 创建一个表示学生信息的结构体
  2. 编写程序,实现华氏温度到摄氏温度的转换
  3. 使用可空类型处理可能为空的年龄输入
  4. 尝试使用记录类型创建一个不可变对象