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 |
| bool | false |
| 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(内容相同)
小结
- 值类型:直接存储值,包括整数、浮点、布尔、字符、结构、枚举
- 引用类型:存储引用,包括类、接口、数组、委托、字符串
- 可空类型:使用
?或Nullable<T>表示可为空 - 类型转换:隐式转换、显式转换、as/is 运算符
- 记录类型:C# 9 引入的引用类型,默认值相等比较
练习
- 创建一个表示学生信息的结构体
- 编写程序,实现华氏温度到摄氏温度的转换
- 使用可空类型处理可能为空的年龄输入
- 尝试使用记录类型创建一个不可变对象