【原理】Struct 和 Class 辨析

【从UnityURP开始探索游戏渲染】专栏-直达

C# 结构体:

  • 可以单独赋值,但需要注意结构体是值类型
  • 如果结构体变量是局部变量,需要先完全初始化后才能使用
  • 如果是类成员字段,可以直接修改单个字段

在C#中,结构体(struct)是值类型,作为局部变量时‌必须完全初始化‌后才能使用。

错误示例(未完全初始化)

cs 复制代码
csharp
struct Point {
    public int X;
    public int Y;
}

void Demo() {
    Point p;// 声明局部结构体变量(未初始化)
    Console.WriteLine(p.X);// 编译错误:使用了未赋值的局部变量'p'
}

‌问题 ‌:结构体p的字段X和Y未被赋值,直接访问会导致编译错误。


正确示例(完全初始化)

方法1:逐个字段赋值

cs 复制代码
csharp
Point p;
p.X = 10;// 显式初始化X
p.Y = 20;// 显式初始化Y
Console.WriteLine(p.X);// 输出:10

方法2:使用构造函数初始化

cs 复制代码
csharp
Point p = new Point();// 调用默认构造函数(数值类型字段初始化为0)
Console.WriteLine(p.X);// 输出:0// 或自定义构造函数
Point p2 = new Point(10, 20);// 假设定义了构造函数

方法3:初始化时直接赋值

cs 复制代码
csharp
Point p = new Point { X = 10, Y = 20 };// 对象初始化器

关键规则

  1. ‌局部变量‌必须显式初始化所有字段后才能使用。
  2. ‌类成员字段 ‌会自动初始化为默认值(如int为0),无需手动初始化。
  3. 通过new调用默认构造函数时,所有字段会被置为默认值(等同于完全初始化)。

注意:C#的结构体设计强调明确性,避免意外使用未初始化的内存。

在C#中,结构体作为‌类成员字段‌和‌局部变量‌时的行为不同,主要体现在是否需要完全初始化后才能修改单个字段:

一、类成员字段(可直接修改单个字段)

cs 复制代码
csharp
class MyClass {
    Point p;// 结构体作为类成员字段(自动初始化为默认值)void Modify() {
        p.X = 10;// 直接修改单个字段(无需完全初始化)
    }
}

‌说明‌:

类中的结构体字段会被自动初始化为默认值(int为0),因此可以直接修改单个字段。

二、非类成员字段(需先完全初始化)

情况1:局部变量(必须完全初始化)

cs 复制代码
csharp
void Demo() {
    Point p;// 局部结构体变量(未初始化)
    p.X = 10;// 编译错误:使用了未赋值的局部变量'p'

// 必须先完全初始化
    Point p2 = new Point();// 调用默认构造函数(所有字段置为0)
    p2.X = 10;// 合法
}

情况2:方法参数(按值传递时)

cs 复制代码
csharp
void ModifyPoint(Point p) {
    p.X = 100;// 修改的是副本,不影响原始值
}

void Caller() {
    Point p = new Point { X = 1, Y = 2 };
    ModifyPoint(p);
    Console.WriteLine(p.X);// 输出:1(原值未变)
}

情况3:ref或out参数(可修改原始值)

cs 复制代码
csharp
void ModifyRefPoint(ref Point p) {
    p.X = 100;// 直接修改原始值
}

void Caller() {
    Point p = new Point { X = 1, Y = 2 };
    ModifyRefPoint(ref p);
    Console.WriteLine(p.X);// 输出:100
}

关键区别总结

‌场景‌ 能否直接修改单个字段 原因
类成员字段 ✅ 可以 自动初始化为默认值
局部变量 ❌ 不可以 未初始化的局部变量禁止访问(编译器强制要求)
方法参数(值传递) ❌ 修改的是副本 结构体按值传递,方法内修改不影响调用方
ref/out参数 ✅ 可以 直接操作原始值的引用

‌最佳实践‌:对结构体局部变量始终显式初始化(通过new或赋值所有字段),避免未定义行为。

在C#中,class(类)和struct(结构体)存在本质区别,与C++中的差异点(如默认访问权限)完全不同‌。C#的主要区别围绕‌ 值类型(struct)与引用类型(class) 的特性展开:

一、核心行为差异

‌特性‌ ‌**Struct(结构体)**‌ ‌**Class(类)**‌
‌类型本质‌ 值类型(直接存储数据) 引用类型(存储数据的内存地址)
‌内存分配位置‌ 栈或父对象内联存储 托管堆(由GC管理)
‌赋值行为‌ 复制整个数据(深拷贝) 复制引用(浅拷贝)
‌参数传递‌ 默认按值传递(方法内修改不影响原变量) 默认按引用传递(方法内修改影响原对象)
‌是否支持继承‌ ❌ 不可继承(只能实现接口) ✅ 支持完整继承链和多态
‌**能否为null**‌ ❌ 不可直接为null(需用Nullable<T>) ✅ 可直接赋值为null

在C#中,结构体(struct)是值类型,不能直接赋值为null。若需要表示"无值"状态,需使用Nullable<T>(简写为T?)。以下是具体示例:

1. ‌直接赋值为null(错误示例)‌

cs 复制代码
csharp
struct Point { public int X, Y; }

Point p = null;//  ❌ 编译错误:无法将null转换为值类型

2. ‌正确使用Nullable<T>‌

方法1:显式声明Nullable<T>

cs 复制代码
csharp
Nullable<Point> nullablePoint = null;// ✅ 合法if (!nullablePoint.HasValue) {
    Console.WriteLine("Point is null");
}

方法2:使用语法糖T?

cs 复制代码
csharp
Point? nullablePoint = null;// ✅ 等价于Nullable<Point>

方法3:操作可空结构体

cs 复制代码
csharp
Point? p = new Point { X = 10, Y = 20 };
p = null;// ✅ 可重新赋值为null// 安全访问(需判断HasValue或使用null条件运算符)
Console.WriteLine(p?.X ?? -1);// 输出:-1(因p为null)

3. ‌与引用类型对比‌

cs 复制代码
csharp
class MyClass { public int Data; }

MyClass obj = null;// ✅ 类可直接为null(引用类型)
Point? p = null;// ✅ 结构体需通过Nullable<T>实现

关键点

  • ‌值类型默认不可为null ‌:如int、DateTime、自定义struct等。
  • ‌Nullable原理 ‌:本质是结构体System.Nullable<T>,通过HasValue和Value属性管理状态。
  • ‌应用场景 ‌:数据库字段(可能为NULL)、可选参数等。

HLSL (着色器语言):

  • 结构体字段可以单独赋值
  • 但要注意HLSL中的结构体主要用于数据封装,通常在CPU端初始化后传入GPU
  • 在着色器代码中可以修改单个字段值

C++ 结构体:

  • 可以单独赋值结构体中的字段
  • C++中结构体和类非常相似(主要区别是默认访问权限)
  • 无论是栈上还是堆上分配的结构体实例,都可以直接访问和修改成员

在C++中,结构体(struct)和类(class)功能几乎完全一致,其核心区别在于‌默认访问权限 ‌和‌默认继承方式‌:

核心区别对比

‌维度‌ ‌结构体struct‌ ‌类class‌
‌默认成员访问权限‌ 默认为 public(成员可被外部直接访问) 默认为 private(成员仅内部/友元可访问)
‌默认继承方式‌ 默认为 public 继承(基类成员权限保持不变) 默认为 private 继承(基类成员在派生类中变为 private)

【从UnityURP开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)

相关推荐
C^h4 小时前
c++ string
开发语言·c++
raindayinrain4 小时前
c++高性能--原子操作,无锁编程,操作顺序
开发语言·c++·性能优化
学逆向的4 小时前
C++ 合并命名空间
开发语言·c++·网络安全
Zhao-Jichao4 小时前
VS2026 打包 C++ 程序生成 EXE,借助 Installer Project 扩展工具
开发语言·c++
学逆向的5 小时前
C 局部静态变量
c语言·开发语言·网络安全
小徐不徐说5 小时前
C++ 接口与插件设计:从工厂注册到 Qt 动态插件
数据库·c++·qt·系统架构·程序设计
大都督会赢的5 小时前
C++第一节课
开发语言·c++
UIU1146 小时前
P1233 [ICPC 2001 Taejon R] 木棍加工
数据结构·c++·算法·动态规划
“AI国潮设计-小江”6 小时前
【AIGC实战】Python+Stable Diffusion打造“英歌舞财神”IP,解锁“马到成功”等爆款情绪营销文案设计
开发语言·人工智能·python·prompt·aigc
小王C语言6 小时前
Qt常用控件:容器类控件,标题分组框、标签页(浏览器标签)
开发语言·qt