【C#】C# 中的 enum、struct 和 class 对比总结

文章目录


引言

在 C# 类型系统中,enumstructclass 是三种最基础且最重要的类型定义方式。它们分别服务于不同的场景,理解其本质区别和适用场景,对于编写高质量的代码至关重要。本文将系统性地总结这三种类型的特性、差异及使用建议。


一、三者概览

类型 分类 存储位置 核心用途 典型场景
enum 值类型 定义一组命名常量 状态、选项、类型标识
struct 值类型 封装小型数据组 坐标、参数、数据传输对象
class 引用类型 定义复杂业务对象 服务、管理器、实体模型

二、enum:常量的集合

本质

enum 是值类型,本质上是整数类型(默认为 int)的封装,用于定义一组相关的命名常量。

核心特点

  • 简单纯粹:只能包含枚举成员,每个成员对应一个常量值
  • 类型安全:避免使用魔法数字,编译时检查
  • 支持标志位 :通过 [Flags] 特性支持位运算组合

代码示例

csharp 复制代码
// 基础枚举:订单状态
public enum OrderStatus
{
    Pending = 1,      // 待支付
    Paid = 2,         // 已支付
    Shipped = 3,      // 已发货
    Delivered = 4,    // 已送达
    Cancelled = 5     // 已取消
}

// 标志位枚举:用户权限
[Flags]
public enum Permission
{
    None = 0,
    Read = 1 << 0,    // 1
    Write = 1 << 1,   // 2
    Delete = 1 << 2,  // 4
    Admin = Read | Write | Delete  // 7
}

// 使用示例
public class Order
{
    public OrderStatus Status { get; set; }
}

// 权限组合
Permission userPerm = Permission.Read | Permission.Write;
if (userPerm.HasFlag(Permission.Write))
{
    Console.WriteLine("用户有写入权限");
}

适用场景

  • 状态机:订单状态、审批状态、任务状态
  • 选项配置:用户角色、权限级别、支付方式
  • 类型标识:日志级别、错误类型、文件类型
  • 方向/方位:方向(上/下/左/右)、星期几、月份

三、struct:轻量级数据容器

本质

struct 是值类型,用于封装一组相关的数据字段,通常代表一个轻量级的、不可变的数据结构。

核心特点

  • 值语义:赋值时复制整个数据,修改互不影响
  • 栈分配:小对象分配和释放效率高,无 GC 压力
  • 不可变性建议:微软推荐将 struct 设计为不可变类型
  • 限制:不能继承类,不能定义无参构造函数(C# 10 前)

代码示例

csharp 复制代码
// 推荐:不可变结构体
public struct Color
{
    public byte R { get; }
    public byte G { get; }
    public byte B { get; }
    
    public Color(byte r, byte g, byte b)
    {
        R = r;
        G = g;
        B = b;
    }
    
    public string ToHex() => $"#{R:X2}{G:X2}{B:X2}";
}

// 坐标结构体
public struct Point
{
    public double X { get; set; }
    public double Y { get; set; }
    
    public double DistanceTo(Point other)
    {
        double dx = X - other.X;
        double dy = Y - other.Y;
        return Math.Sqrt(dx * dx + dy * dy);
    }
}

// 数据传输对象
public struct ProductInfo
{
    public int Id;
    public string Name;
    public decimal Price;
}

赋值行为演示

csharp 复制代码
// struct:值类型,复制整个数据
Point p1 = new Point { X = 10, Y = 20 };
Point p2 = p1;        // 复制 p1 的所有数据
p2.X = 30;            // 只修改 p2
Console.WriteLine(p1.X);  // 输出: 10 (p1 不受影响)

// 对比 class
class PointClass { public int X, Y; }
PointClass c1 = new PointClass { X = 10, Y = 20 };
PointClass c2 = c1;   // c2 和 c1 指向同一个对象
c2.X = 30;            // 修改的是同一个对象
Console.WriteLine(c1.X);  // 输出: 30 (c1 也被修改)

适用场景

  • 数学概念:坐标(Point)、尺寸(Size)、矩形(Rectangle)
  • 颜色值:RGB、ARGB 颜色表示
  • 日期区间:DateRange、TimeRange
  • 数值区间:Range、Interval
  • 轻量级 DTO:频繁传输的小型数据包

四、class:复杂业务对象

本质

class 是引用类型,用于定义具有状态和行为的复杂对象,是面向对象编程的核心。

核心特点

  • 引用语义:赋值时传递引用,多处共享同一实例
  • 堆分配:支持复杂的生命周期管理
  • 完整的 OOP 支持:继承、多态、封装、析构函数
  • 灵活性:可定义无参构造、析构函数、虚方法等

代码示例

csharp 复制代码
// 抽象基类
public abstract class User
{
    public int Id { get; set; }
    public string UserName { get; set; }
    public abstract string GetRole();
    
    public virtual void Login()
    {
        Console.WriteLine($"{UserName} 登录成功");
    }
}

// 派生类
public class Admin : User
{
    public override string GetRole() => "管理员";
    
    public override void Login()
    {
        base.Login();
        Console.WriteLine("管理员权限已激活");
    }
}

public class RegularUser : User
{
    public override string GetRole() => "普通用户";
}

// 服务类(单例模式)
public class UserService
{
    private static UserService _instance;
    private List<User> _users = new List<User>();
    
    private UserService() { }
    
    public static UserService Instance => _instance ??= new UserService();
    
    public void AddUser(User user) => _users.Add(user);
    public List<User> GetAllUsers() => _users;
}

// 实体类
public class ShoppingCart
{
    public int CartId { get; set; }
    private List<Product> _items = new List<Product>();
    
    public void AddItem(Product product)
    {
        _items.Add(product);
    }
    
    public decimal GetTotal()
    {
        return _items.Sum(item => item.Price);
    }
    
    ~ShoppingCart()
    {
        Console.WriteLine($"购物车 {CartId} 已销毁");
    }
}

适用场景

  • 业务实体:用户、订单、产品、客户
  • 服务类:用户服务、邮件服务、数据库服务
  • 管理器:连接池、缓存管理、配置管理
  • 复杂对象:需要继承和多态的领域模型
  • UI 组件:窗体、控件、视图模型

五、关键差异详解

1. 赋值行为对比

csharp 复制代码
// enum:赋值整数常量
OrderStatus status1 = OrderStatus.Paid;
OrderStatus status2 = status1;  // 复制值

// struct:复制全部数据
struct Rectangle { public int Width, Height; }
Rectangle rect1 = new Rectangle { Width = 10, Height = 20 };
Rectangle rect2 = rect1;        // 复制整个结构体
rect2.Width = 30;               // rect1.Width 仍为 10

// class:复制引用
class RectangleClass { public int Width, Height; }
RectangleClass rect3 = new RectangleClass { Width = 10, Height = 20 };
RectangleClass rect4 = rect3;   // 指向同一对象
rect4.Width = 30;               // rect3.Width 变为 30

2. 内存分配与性能

csharp 复制代码
// struct:栈分配,GC 友好
public void ProcessColors()
{
    var colors = new Color[10000];      // 连续内存,访问快
    // 方法结束自动释放,无 GC 压力
}

// class:堆分配,GC 管理
public void ProcessUsers()
{
    var users = new List<User>();       // 堆分配,需 GC 回收
    users.Add(new Admin());
    users.Add(new RegularUser());
    // 需等待 GC 回收
}

3. 类型限制对比

特性 enum struct class
无参构造函数 不支持 有限支持 完全支持
析构函数 不支持 不支持 支持
继承类 不支持 不支持 支持
实现接口 支持 支持 支持
可为 null
默认值 第一个成员 所有字段为默认值 null

六、通用场景示例

综合运用三种类型的实际场景:

场景一:电商系统

csharp 复制代码
// enum:订单状态
public enum OrderStatus
{
    Pending,
    Paid,
    Shipped,
    Completed,
    Cancelled
}

// enum:支付方式
public enum PaymentMethod
{
    CreditCard,
    Alipay,
    WeChat,
    BankTransfer
}

// struct:金额(不可变值类型)
public struct Money
{
    public decimal Amount { get; }
    public string Currency { get; }
    
    public Money(decimal amount, string currency)
    {
        Amount = amount;
        Currency = currency;
    }
    
    public Money Add(Money other)
    {
        if (Currency != other.Currency)
            throw new InvalidOperationException("货币类型不一致");
        return new Money(Amount + other.Amount, Currency);
    }
}

// class:订单实体
public class Order
{
    public int OrderId { get; set; }
    public OrderStatus Status { get; set; }
    public PaymentMethod PaymentMethod { get; set; }
    public Money TotalAmount { get; set; }
    private List<OrderItem> _items = new List<OrderItem>();
    
    public void AddItem(Product product, int quantity)
    {
        _items.Add(new OrderItem(product, quantity));
        RecalculateTotal();
    }
    
    private void RecalculateTotal()
    {
        decimal total = _items.Sum(item => item.Subtotal.Amount);
        TotalAmount = new Money(total, "CNY");
    }
    
    public void Pay(PaymentMethod method)
    {
        PaymentMethod = method;
        Status = OrderStatus.Paid;
    }
}

场景二:图形处理系统

csharp 复制代码
// struct:颜色(值类型)
public struct Color
{
    public byte R, G, B, A;
    public Color(byte r, byte g, byte b, byte a = 255)
    {
        R = r; G = g; B = b; A = a;
    }
}

// struct:坐标点
public struct Point
{
    public int X, Y;
    public Point(int x, int y) { X = x; Y = y; }
}

// class:图形基类(引用类型)
public abstract class Shape
{
    public Color FillColor { get; set; }
    public abstract double GetArea();
    public abstract void Draw();
}

public class Rectangle : Shape
{
    public Point Position { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
    
    public override double GetArea() => Width * Height;
    public override void Draw() { }
}

场景三:权限管理系统

csharp 复制代码
// enum:权限标志位
[Flags]
public enum Permission
{
    None = 0,
    View = 1,
    Create = 2,
    Edit = 4,
    Delete = 8,
    Full = View | Create | Edit | Delete
}

// struct:权限组(轻量级组合)
public struct PermissionGroup
{
    public string Name { get; }
    public Permission Permissions { get; }
    
    public PermissionGroup(string name, Permission perms)
    {
        Name = name;
        Permissions = perms;
    }
    
    public bool HasPermission(Permission perm) => Permissions.HasFlag(perm);
}

// class:用户服务
public class UserService
{
    private Dictionary<string, PermissionGroup> _groups;
    
    public UserService()
    {
        _groups = new Dictionary<string, PermissionGroup>();
    }
    
    public void AddGroup(PermissionGroup group)
    {
        _groups[group.Name] = group;
    }
    
    public bool CheckPermission(string groupName, Permission required)
    {
        return _groups.TryGetValue(groupName, out var group) &&
               group.HasPermission(required);
    }
}

七、选择指南

使用 enum 当:

  • ✅ 需要定义一组相关的常量值(如状态、类型、选项)
  • ✅ 替代魔法数字,增强代码可读性
  • ✅ 需要位标志组合(使用 [Flags]
  • ✅ 做 switch-case 判断

使用 struct 当:

  • ✅ 数据量小(建议 < 16 字节)
  • ✅ 代表单一的值(如坐标、颜色、范围)
  • ✅ 生命周期短暂,频繁创建销毁
  • ✅ 希望值语义,数据独立
  • ✅ 不需要继承和多态

使用 class 当:

  • ✅ 对象包含复杂行为和状态
  • ✅ 需要继承和多态
  • ✅ 对象较大,复制成本高
  • ✅ 需要在多处共享同一实例
  • ✅ 需要实现 IDisposable 进行资源管理

八、最佳实践总结

1. enum 最佳实践

csharp 复制代码
// ✅ 显式指定值,便于序列化
public enum LogLevel
{
    Debug = 10,
    Info = 20,
    Warning = 30,
    Error = 40
}

// ✅ 位标志使用 2 的幂
[Flags]
public enum FileAccess
{
    None = 0,
    Read = 1,
    Write = 2,
    Execute = 4
}

// ❌ 避免复杂的逻辑判断
// ❌ 不要在枚举中定义方法(使用扩展方法替代)

2. struct 最佳实践

csharp 复制代码
// ✅ 设计为不可变类型
public struct Point
{
    public int X { get; }
    public int Y { get; }
    public Point(int x, int y) { X = x; Y = y; }
}

// ✅ 保持结构体小巧
// ✅ 需要修改时传递 ref 参数
public void UpdatePoint(ref Point point, int dx, int dy) { }

// ❌ 避免在结构体中定义引用类型字段(会导致复制成本增加)
// ❌ 避免频繁装箱拆箱

3. class 最佳实践

csharp 复制代码
// ✅ 遵循 SOLID 原则
// ✅ 需要继承时设计抽象基类
public abstract class Repository<T> { }

// ✅ 考虑使用接口定义契约
public interface IUserService { }

// ✅ 大型对象实现 IDisposable
public class DatabaseConnection : IDisposable
{
    public void Dispose() { /* 释放资源 */ }
}

九、性能考量速查表

操作 enum struct class
创建小对象(<16B) 最快 慢(堆分配)
创建大对象 N/A 慢(复制成本高) 快(引用传递)
传递参数 快(值复制) 小对象快,大对象慢 快(引用传递)
GC 压力
数组访问 连续内存 分散内存

结语

enumstructclass 是 C# 类型系统的三大基石,各有其独特的设计哲学和适用场景:

  • enum:用命名常量代替魔法数字,让代码更清晰
  • struct:用值语义封装轻量数据,让性能更高效
  • class:用引用语义构建复杂对象,让设计更灵活

理解并善用这三种类型,是写出高质量 C# 代码的关键。在实际开发中,根据数据大小、生命周期、共享需求和性能要求,选择最合适的类型,才能构建出既健壮又高效的应用程序。

相关推荐
cui_ruicheng2 小时前
C++ 新特性(下):可变参数模板与 STL 扩展机制
开发语言·c++·c++11
拾荒的路由2 小时前
HOT100DAY9记录用
数据结构·算法·leetcode
沙雕不是雕又菜又爱玩2 小时前
leetcode第7题 整数反转(C++)
算法·leetcode
m0_726965982 小时前
面面面(2)
java·开发语言
桦02 小时前
【C复习】
c语言·开发语言
JavaWeb学起来2 小时前
Python学习教程(一)环境安装,基本数据类型,变量
开发语言·python·python基础
迷藏4942 小时前
# 发散创新:用 Rust实现高性能测试框架的底层逻辑与实战演练
java·开发语言·后端·python·rust
路小雨~2 小时前
机器学习基础算法学习笔记
学习·算法·机器学习
chushiyunen2 小时前
python单例模式、大模型一次加载多次复用
开发语言·python·单例模式