C# 数据类型
值类型与引用类型、内置类型、默认值、以及 `var` 与 `dynamic`。
Key Points值类型存在栈上(或内联在对象里),引用类型指向堆上的对象。
两大类
| Category | Types | Assignment |
|---|---|---|
| 值类型 | int double bool char struct enum | 复制整个值 |
| 引用类型 | string class array delegate object | 复制引用 |
C#
// 值类型:复制
int a = 10;
int b = a;
b = 20;
Console.WriteLine($"a={a} b={b}");
// 引用类型:共享
int[] x = { 1, 2 };
int[] y = x;
y[0] = 99;
Console.WriteLine($"x[0]={x[0]}");Output
a=10 b=20
x[0]=99内置类型
| Type | Size | Range | Alias |
|---|---|---|---|
Int32 | 4 字节 | ±21 亿 | int |
Int64 | 8 字节 | ±9.2e18 | long |
Int16 | 2 字节 | ±32767 | short |
Byte | 1 字节 | 0~255 | byte |
Single | 4 字节 | 约 7 位有效数字 | float |
Double | 8 字节 | 约 15 位 | double |
Decimal | 16 字节 | 28 位,精确十进制 | decimal |
Boolean | 1 字节 | true/false | bool |
Char | 2 字节 | UTF-16 单元 | char |
String | 引用类型 | 不可变 | string |
金额用 decimal
C#
double d = 0.1 + 0.2;
Console.WriteLine(d);
decimal m = 0.1m + 0.2m;
Console.WriteLine(m);Output
0.30000000000000004
0.3**Money, tax rates and prices must use
decimal.** double is binary floating point, so 0.1 is inexact and errors accumulate into real money problems. decimal literals need the m suffix.默认值
C#
Console.WriteLine(default(int));
Console.WriteLine(default(bool));
Console.WriteLine(default(double));
Console.WriteLine(default(char) == '\0');
Console.WriteLine(default(string) == null);
// 值类型不能直接赋 null,要加 ?
int? n = null;
Console.WriteLine(n.HasValue);Output
0
False
0
True
True
Falsevar 与 dynamic
C#
var a = 10; // 编译期推断为 int,之后不能改成 string
var list = new List<int>();
var dict = new Dictionary<string, int>();
dynamic b = 10; // 运行期决定类型
b = "现在变字符串了";
Console.WriteLine(b);
Console.WriteLine(a.GetType().Name);Output
现在变字符串了
Int32var is pure syntax sugar; the type is fixed at compile time with no performance or safety cost. dynamic defers checking to runtime — slower and prone to runtime failures.
两大类
| 类别 | 类型 | 赋值行为 |
|---|---|---|
| 值类型 | int double bool char struct enum | 复制整个值 |
| 引用类型 | string class array delegate object | 复制引用 |
C#
// 值类型:复制
int a = 10;
int b = a;
b = 20;
Console.WriteLine($"a={a} b={b}");
// 引用类型:共享
int[] x = { 1, 2 };
int[] y = x;
y[0] = 99;
Console.WriteLine($"x[0]={x[0]}");Output
a=10 b=20
x[0]=99内置类型
| 类型 | 大小 | 范围 | 关键字 |
|---|---|---|---|
Int32 | 4 字节 | ±21 亿 | int |
Int64 | 8 字节 | ±9.2e18 | long |
Int16 | 2 字节 | ±32767 | short |
Byte | 1 字节 | 0~255 | byte |
Single | 4 字节 | 约 7 位有效数字 | float |
Double | 8 字节 | 约 15 位 | double |
Decimal | 16 字节 | 28 位,精确十进制 | decimal |
Boolean | 1 字节 | true/false | bool |
Char | 2 字节 | UTF-16 单元 | char |
String | 引用类型 | 不可变 | string |
金额用 decimal
C#
double d = 0.1 + 0.2;
Console.WriteLine(d);
decimal m = 0.1m + 0.2m;
Console.WriteLine(m);Output
0.30000000000000004
0.3**金额、税率、单价一律用
decimal**。double 是二进制浮点,0.1 存不准,累加几千次后误差会变成真金白银的问题。decimal 字面量要加 m 后缀。默认值
C#
Console.WriteLine(default(int));
Console.WriteLine(default(bool));
Console.WriteLine(default(double));
Console.WriteLine(default(char) == '\0');
Console.WriteLine(default(string) == null);
// 值类型不能直接赋 null,要加 ?
int? n = null;
Console.WriteLine(n.HasValue);Output
0
False
0
True
True
Falsevar 与 dynamic
C#
var a = 10; // 编译期推断为 int,之后不能改成 string
var list = new List<int>();
var dict = new Dictionary<string, int>();
dynamic b = 10; // 运行期决定类型
b = "现在变字符串了";
Console.WriteLine(b);
Console.WriteLine(a.GetType().Name);Output
现在变字符串了
Int32var 只是语法糖,类型在编译期就固定了,完全不影响性能和类型安全。dynamic 才是真的动态——类型检查推迟到运行期,会慢且容易在运行时炸。