C#基础知识 3:数据类型
3.1 值类型
值类型 是直接存储在栈(stack)中的数据类型。值类型包括基本数据类型(如 int
, float
, double
, bool
, char
)和结构体(struct
)。以下是值类型的详细讲解,包括其优点、缺点以及代码示例。
3.1.1 值类型的基本概念
值类型 是直接存储在栈中的数据类型。值类型的变量直接包含数据的值。当一个值类型变量被赋值给另一个变量时,会创建数据的副本。
示例:
csharp
int a = 10;
int b = a; // b 是 a 的副本
b = 20; // 修改 b 不会影响 a
Console.WriteLine(a); // 输出: 10
Console.WriteLine(b); // 输出: 20
3.1.2 值类型的主要类别
-
基本数据类型:
int
:32位整数。float
:32位单精度浮点数。double
:64位双精度浮点数。bool
:布尔值(true
或false
)。char
:16位Unicode字符。byte
:8位无符号整数。short
:16位有符号整数。long
:64位有符号整数。decimal
:128位十进制数。sbyte
:8位有符号整数。ushort
:16位无符号整数。uint
:32位无符号整数。ulong
:64位无符号整数。
-
结构体(
struct
):- 用户定义的复合数据类型。
- 结构体可以包含字段、方法、属性等。
示例:
csharp
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
public void Display()
{
Console.WriteLine($"Point: ({X}, {Y})");
}
}
3.1.3 值类型的优点
-
性能:
- 值类型直接存储在栈中,访问速度更快。
- 没有堆分配和垃圾回收的开销。
-
内存效率:
- 值类型占用的内存较小,适合存储大量数据。
- 避免了堆内存分配的开销。
-
简单性:
- 值类型的使用简单直观,易于理解和管理。
- 没有引用类型的复杂性。
-
线程安全:
- 值类型的副本是独立的,不会出现线程安全问题。
- 适合多线程环境。
-
避免空引用:
- 值类型不能为
null
(除非使用可空值类型)。 - 减少了空引用异常的风险。
- 值类型不能为
3.1.4 值类型的缺点
-
内存开销:
- 每个值类型变量都会在栈中分配内存,可能导致内存消耗增加。
- 对于大型结构体,内存开销可能较大。
-
复制开销:
- 当值类型变量被赋值给另一个变量时,会创建数据的副本。
- 对于大型结构体,复制开销可能较大。
-
不可变性:
- 值类型的变量是不可变的(除非使用
ref
关键字)。 - 修改值类型变量时,会创建新的副本。
- 值类型的变量是不可变的(除非使用
-
缺乏继承:
- 值类型不能继承自其他类或结构体。
- 限制了代码的重用性和灵活性。
-
默认值:
- 值类型有默认值(如
int
的默认值为0
)。 - 在某些情况下,可能需要显式初始化。
- 值类型有默认值(如
3.1.5 值类型的代码示例
以下是一些详细的代码示例,展示了如何声明和使用值类型。
示例1:基本数据类型
文件1:Program.cs
csharp
using System;
class Program
{
static void Main(string[] args)
{
int a = 10;
int b = a; // b 是 a 的副本
b = 20; // 修改 b 不会影响 a
Console.WriteLine(a); // 输出: 10
Console.WriteLine(b); // 输出: 20
float f = 3.14f;
double d = 3.14159;
bool isTrue = true;
char c = 'A';
byte b1 = 255;
short s = 32767;
long l = 9223372036854775807L;
decimal dec = 123.456m;
sbyte sb = 127;
ushort us = 65535;
uint ui = 4294967295U;
ulong ul = 18446744073709551615UL;
Console.WriteLine($"int: {a}, float: {f}, double: {d}, bool: {isTrue}, char: {c}");
Console.WriteLine($"byte: {b1}, short: {s}, long: {l}, decimal: {dec}");
Console.WriteLine($"sbyte: {sb}, ushort: {us}, uint: {ui}, ulong: {ul}");
}
}
示例2:结构体
文件1:Point.cs
csharp
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
public void Display()
{
Console.WriteLine($"Point: ({X}, {Y})");
}
}
文件2:Program.cs
csharp
using System;
class Program
{
static void Main(string[] args)
{
Point p1 = new Point();
p1.X = 10;
p1.Y = 20;
p1.Display(); // 输出: Point: (10, 20)
Point p2 = p1; // p2 是 p1 的副本
p2.X = 30;
p2.Display(); // 输出: Point: (30, 20)
p1.Display(); // 输出: Point: (10, 20) // p1 未受影响
}
}
示例3:可空值类型
文件1:Program.cs
csharp
using System;
class Program
{
static void Main(string[] args)
{
int? nullableInt = null;
double? nullableDouble = 3.14;
bool? nullableBool = true;
Console.WriteLine($"nullableInt: {nullableInt}");
Console.WriteLine($"nullableDouble: {nullableDouble}");
Console.WriteLine($"nullableBool: {nullableBool}");
if (nullableInt.HasValue)
{
Console.WriteLine($"nullableInt has value: {nullableInt.Value}");
}
else
{
Console.WriteLine("nullableInt is null");
}
if (nullableDouble.HasValue)
{
Console.WriteLine($"nullableDouble has value: {nullableDouble.Value}");
}
else
{
Console.WriteLine("nullableDouble is null");
}
if (nullableBool.HasValue)
{
Console.WriteLine($"nullableBool has value: {nullableBool.Value}");
}
else
{
Console.WriteLine("nullableBool is null");
}
}
}
示例4:值类型与方法参数
文件1:Program.cs
csharp
using System;
class Program
{
static void Main(string[] args)
{
int a = 10;
Console.WriteLine($"Before: a = {a}"); // 输出: Before: a = 10
Increment(a);
Console.WriteLine($"After: a = {a}"); // 输出: After: a = 10
int b = 20;
Console.WriteLine($"Before: b = {b}"); // 输出: Before: b = 20
IncrementByRef(ref b);
Console.WriteLine($"After: b = {b}"); // 输出: After: b = 21
}
static void Increment(int value)
{
value++;
}
static void IncrementByRef(ref int value)
{
value++;
}
}
通过以上详细讲解和代码示例,您可以更好地理解和使用C#中的值类型。值类型是直接存储在栈中的数据类型,具有高性能和内存效率,但需要注意其复制开销和不可变性。