16-01-C#数据结构源码-附录A-术语表

附录 A:术语表

系列 :C# 与常用数据结构源码剖析 · 附录

使用方式:本表给出本专栏采用的精确口径。具体 API 仍以目标 TFM 契约、参考程序集和对应运行时版本为准。

运行时与工具链

术语 精确口径
CLI ECMA-335 定义的 Common Language Infrastructure,包含 CTS、元数据、CIL、虚执行系统等规范。它不等于某一个 .NET 实现。
CLR Common Language Runtime 的概念和产品称呼,通常指 .NET 执行引擎一类能力,不应用来暗指所有平台都使用 CoreCLR 源码。
CoreCLR 现代 .NET 中的主要运行时实现,位于 dotnet/runtime 的 src/coreclr,包含 VM、GC、RyuJIT 等。
Mono .NET 的另一运行时实现家族,现代源码在 dotnet/runtime/src/mono。Unity 的 Mono 需按 Unity 版本核验,不可自动等同于当前 upstream Mono。
IL2CPP Unity 的脚本后端:将托管 IL 转换为 C++,再使用平台原生工具链 AOT 编译。它不等于 CoreCLR JIT,也不会让托管对象自动变成无 GC 原生对象。
Roslyn C# / Visual Basic 编译器平台与公开分析 API。".NET 8 SDK 的 Roslyn"仍要用 SDK 完整版本和 Roslyn commit 锁定。
IL / CIL CLI 定义的中间指令集。反编译工具显示的 C# 是对 IL 和元数据的重建,不是原始源码或 Roslyn 内部树。
JIT 在运行期将 IL/中间表示编译为机器码。具体优化受运行时版本、分层编译、PGO、架构和调用形状影响。
AOT 在执行前产生机器码的策略总称。NativeAOT、ReadyToRun 与 IL2CPP 的管线、兼容性和产物不同。
TFM Target Framework Moniker,例如 net8.0。它指定编译时目标 API 表面,不唯一决定实际运行时实现和硬件。
Reference assembly 用于编译的 API 契约程序集,通常不包含可用的实现方法体。它回答"目标 TFM 能否调用"。
Runtime / implementation assembly 实际执行的运行时与类库实现。同一 TFM 可在不同 patch、OS、架构或 Unity 后端上展现不同私有实现和性能。

源码阅读与证据

术语 精确口径
公共契约 文档、语言/平台规范、reference assembly 与公开测试所承诺的可观察行为。应用可依赖契约,不应依赖私有字段名。
实现事实 固定版本中可从源码/二进制验证的算法、字段、阈值和优化;版本升级时可改变。
Tag / commit 用于锁定仓库状态的发行标签或提交 ID。tag 便于阅读发行版,commit SHA 提供更精确的可重现坐标。
main 分支 开发中的移动目标,可包含尚未发布改动。不能用当前 main 证明 .NET 8、.NET 9 或某 Unity 版本必然如此。
结构化节选 保留真实方法和关键分支,却删除条件编译、特性、快路径等细节的教学代码。必须标明不可直接替换原文件。
伪代码 / 概念转换 用来解释语义或算法,不承诺字段名、控制流、IL 或可编译性与任何发行版逐字相同。
可复现实验 同时保存源码、依赖、完整环境、输入分布、正确性 oracle、原始报告和随机种子的实验。

内存、引用与所有权

术语 精确口径
GC 根据可达性管理托管对象生命周期的机制。对象不可达不表示进程内存立即下降,Dispose 也不普遍等于回收托管对象。
SOH Small Object Heap,CoreCLR GC 中通常容纳未达大对象阈值的对象,包含分代区域。准确布局和策略必须按运行时验证。
LOH Large Object Heap,CoreCLR 将达到当前大对象阈值的特定对象放入的区域。常见阈值约 85,000 字节,但边界、对齐、数组特例、回收与压缩是版本/配置事实,不是业务契约。
POH Pinned Object Heap,CoreCLR 中用于某些预先固定对象的专用堆。一个对象被短期 fixed/pin 不意味着它必然搬到 POH。
写屏障 托管引用写入时配合 GC 维护卡表/记忆集等数据的运行时机制。它不是普通多线程 memory barrier 的同义词。
装箱 / 拆箱 值类型值转换为兼容引用表示,以及从装箱对象取回值类型值的操作。泛型、constrained call 和 JIT 可改变实际代价,不能仅根据接口名猜测。
ref struct 受 C# ref-safety 规则约束、不能普通地装箱或作为任意堆对象字段的值类型。"只能存在栈上"是误导性简化:JIT 可使局部留在寄存器,Span<T> 也可指向托管堆、原生内存或 stackalloc 区域;关键是值本身不能逃逸出合法生命期。
Span<T> 对连续 T 区域的借用视图,不拥有内存。创建/切片 Span 通常不需要为元素再分配数组,但这不保证整个方法、解析器或底层 owner 绝对零分配。
Memory<T> 可存入堆对象并跨异步边界保存的连续内存视图。它不是 owner,不会自动延长数组池租期或 IMemoryOwner<T> 生命期。
Owner 对资源生命期与最终释放/归还负唯一责任的逻辑主体。owner 可是数组本身的持有者、IMemoryOwner<T>、原生容器或业务协议的当前层。
View / borrow 不负责释放底层资源的视图/借用。其有效期不得超过 owner,也不自动获得不可变或线程安全。
Pinning 使托管对象在某时段不被移动,以便取得稳定地址。pin 的作用域必须覆盖 native 使用,长期 pin 的成本需按 GC 实现测量。

类型系统与泛型

术语 精确口径
值类型 变量通常直接包含该类型的值表示;复制变量会复制值。值类型可以位于对象字段、数组元素、栈帧或寄存器,不能简化成"总在栈上"。
引用类型 变量保存对对象的托管引用,多个变量可以指向同一对象。复制引用不会深复制对象;对象位置及 GC 行为由运行时决定。
对象身份 两个引用是否指向同一对象的关系。身份相等与成员值相等是两种问题,不能用业务 Equals 代替所有引用身份判断。
值相等 根据类型定义比较内容或业务键。若类型用于哈希集合,Equals 为真必须推出 GetHashCode 相同;反向不要求成立。
record 编译器生成值相等、打印、解构或克隆相关成员的一类声明形式;具体合成成员随 record class/struct 和自定义成员变化。它不自动深度不可变。
可空值类型 Nullable<T>,表示值类型的"有值/无值"状态。它与可空引用类型注解不是同一种运行时表示。
可空引用类型 C# 编译期流分析与注解系统,主要通过警告表达 null 契约;它不会给引用包一层运行时容器,也不阻止反射、旧程序集或错误抑制传入 null。
泛型具现化 CLI 元数据保留类型参数与闭合构造,运行时再决定具体代码特化、共享和调用适配。不能把它概括成"每个 T 都复制一份机器码"。
泛型代码共享 多个泛型实例复用一份机器码,并通过运行时上下文处理类型相关信息。引用类型常可共享,值类型和 AOT 后端的具体策略需按实现验证。
泛型约束 对类型参数可用操作和允许实参的静态限制,如 class、struct、unmanaged、接口或构造约束。约束不是运行时性能保证。
unmanaged 递归不含托管引用的类型约束,允许某些指针和 sizeof 用法。它不等于任意 ABI 下都 blittable,也不保证 packing、bool 宽度或端序匹配。
方差 泛型接口或委托在引用转换中的协变/逆变规则。可变集合通常保持不变性;数组协变是历史规则,会把部分类型错误推迟到运行时。
ref / byref 对存储位置的受限别名,而不是普通对象引用。其可写性、逃逸范围、跨调用和跨挂起点规则由 C# ref-safety 约束。
in / ref readonly 以只读 byref 方式传递或返回位置,主要避免某些大值复制并限制写入。编译器仍可能为非 readonly 成员调用产生防御性复制。
dynamic 将成员绑定推迟到运行时 binder 的静态类型标记。它不是反射的别名,也不保证在裁剪/AOT 下任意调用形状都可用。
Blittable 托管和非托管表示可按目标互操作规则直接复制的一类类型。定义受封送器/API/平台影响,不应仅凭 unmanaged 约束推断。

集合与算法

术语 精确口径
Count 当前逻辑元素数。它不等于底层数组长度、容量、哈希表 occupancy 或进程内存占用。
Capacity 容器在再次扩容前可容纳的元素规模或内部数组长度。预留容量能减少扩容,但会增加驻留内存,且不保证整条路径零分配。
扩容 分配更大存储并复制/重建索引的过程,通常是单次 O(n)。支持扩容的集合仍可能给出连续插入的均摊 O(1)。
负载因子 哈希表有效条目或占用槽位与容量的关系,用于决定扩容与探测成本。具体阈值属于固定版本实现,不是 Dictionary 公共契约。
哈希冲突 不相等键产生相同桶位置或哈希码的情况。哈希表必须继续用相等比较区分;存在冲突不表示实现错误。
Comparer 定义排序关系的对象;结果应满足目标算法要求的自反/反对称/传递等性质。排序相等不必等于对象身份相同。
Equality comparer 成对定义相等与哈希的对象。相等键必须同哈希;错误或可变 comparer 会破坏查找语义,而不只是变慢。
可变键 进入哈希表后,参与哈希或相等的状态仍可改变的键。修改后条目仍位于旧桶,可能导致查找/删除失败,应使用不可变键或移除后重插。
冲突链 分离链接哈希表中连接同桶候选 Entry 的索引链。它不是对象链的必然形式,也不是所有哈希表实现都采用的方案。
开放寻址 条目直接存储在槽数组中,冲突后按探测序列寻找其他槽。删除通常需要墓碑或等价状态以维持既有探测链。
Free list 容器内部记录可复用槽位的链或索引结构。逻辑删除可以先复用槽位而不缩小底层数组;它与 GC free list 不是同一概念。
稳定顺序 对相等键或保留元素维持原相对顺序的性质。稳定不等于跨运行时确定性,也不等于容器承诺持久枚举顺序。
结构修改版本 集合用来让枚举器检测不允许修改的计数器或令牌。它是 fail-fast 诊断机制,不是线程同步或事务隔离。
迭代器 / 枚举器 分别表示可枚举序列的生成逻辑和一次遍历游标。延迟执行可能重复运行副作用;枚举器是否为 struct、是否装箱取决于静态调用形状。
物化 将延迟序列完整读取到数组、列表、查找表等存储。它建立快照边界并付出时间/内存,不应与"只创建查询描述"混为一谈。
结构共享 不可变集合的新旧版本复用未变化节点。它减少整棵复制,却仍会为修改路径分配节点,也不让节点内引用对象自动不可变。
环形缓冲 用固定或可增长数组配合头尾索引表达逻辑连续队列。发生回绕时逻辑顺序分成两个物理区间,不能把整个有效区当单一切片。
堆 满足父子优先级关系的树形数组结构,常用于优先队列。它不提供完整排序;同优先级元素顺序也通常不稳定。
红黑树 通过颜色、根、红节点与黑高等不变式维持 O(log n) 高度的平衡搜索树。它不是"每次操作后绝对完美平衡"。

异步与并发

术语 精确口径
线程安全 在声明的并发使用范围内保持公共契约。它不自动意味着复合操作原子、公平、无锁、可重入或高吞吐。
原子操作 对其他观察者不可见中间状态的单个契约操作。两个分别原子的步骤组合后通常不再原子,需要锁、CAS 循环或更高层协议。
CAS Compare-And-Swap/CompareExchange:值仍等于期望值时才更新。失败后通常要重新读取并重算;一次 CAS 不是完整无锁算法。
ABA 问题 CAS 只看到值从 A 又回到 A,无法发现中间经历过 B。可用版本戳、不可复用节点或适合平台的回收协议处理。
争用 多个执行者竞争同一锁、原子位置、缓存行或资源造成等待与一致性流量。无显式锁仍可能有原子争用。
伪共享 线程修改逻辑上独立、物理上处于同一缓存行的数据,导致缓存行反复转移。字段相邻不保证一定发生,需结合布局和硬件计数验证。
Happens-before 用来推理写入何时对另一执行者可见的顺序关系。时间上"先执行"不等于语言/运行时内存模型已建立可见性。
Task 表示一次异步操作的最终完成、结果或异常,可被多个观察者等待。Task 不等于线程,也不保证工作已转移到线程池。
ValueTask 可避免特定同步完成路径 Task 分配的值型 awaitable。实例通常有更严格的消费规则;无证据地全面替换 Task 会增加复杂度。
Awaiter 实现 GetAwaiter 协议并决定完成检查、continuation 注册和结果获取的对象/结构。await 的调度语义来自具体 awaiter,而不是关键字固定保证。
异步状态机 编译器把 async 方法重写成的状态与恢复逻辑。只有跨挂起点仍活跃的值需要保存;真正挂起时状态机可获得堆上稳定身份。
Continuation 等待完成后恢复的后续工作。在哪个线程、上下文或 PlayerLoop 阶段执行取决于 awaiter、上下文和调度器。
SynchronizationContext 提供环境特定 continuation 投递策略的抽象。捕获上下文不等于对象仍存活,也不保证某个 Unity PlayerLoop 阶段。
取消 通过 token 等信号请求协作终止的协议。收到请求不表示底层 I/O 已停止、资源已释放或任务一定进入 Canceled 状态。
完成 / 故障 / 取消 三种需要分别建模的终止维度。管道 writer 完成不等于所有读者取消;某次等待取消也不等于共享通道关闭。
Async stream 以 IAsyncEnumerable<T>/IAsyncEnumerator<T> 表达可异步等待下一项的序列。它仍需处理取消、DisposeAsync、重复枚举和生产速度。
Channel 同时建模读写端、等待、容量、完成和故障的生产消费原语。它不是"加锁 Queue"的同义词,顺序和丢弃策略由选项决定。

性能测量

术语 精确口径
延迟 单次操作从开始到结束的时间,需说明计时边界和分布。平均延迟不能代替 P95/P99 等尾部指标。
吞吐 单位时间完成的工作量。批处理可提高吞吐却增加单项等待;吞吐和延迟不是可互换的一个数字。
帧时间 一帧各 CPU/GPU 阶段耗时及其同步关系。FPS 是倒数式汇总,会掩盖偶发慢帧和主线程尖峰。
CPU time / wall-clock CPU time 是线程实际消耗处理器的时间;wall-clock 包含等待、调度和 I/O。阻塞优化可能降低其中一个却不改变另一个。
分配率 单位时间或每操作分配的托管字节/对象数,不等于当前存活堆、工作集或 GC 暂停。
Retained memory 因可达引用链仍被保留的内存。对象池可能降低分配率却提高 retained memory,二者必须分别观察。
工作集 操作系统当前驻留于物理内存的进程页近似量,不等于托管堆大小,也不等于进程所有虚拟地址空间。
GC 暂停 应用线程因回收协调而停顿的时间与分布。分配量、堆大小和暂停相关但不能互相直接换算。
基线 修改前在固定环境、输入和正确性条件下保存的原始结果。没有同口径基线,优化后的单个数字无法归因。
微基准 隔离小段代码机制成本的实验。它不能自动代表真实请求、Unity PlayerLoop、缓存争用、I/O 或长时间 GC 稳态。
暖机 让 JIT tier、动态 PGO、缓存、池和数据页进入目标状态。冷启动也是需求时,应另设实验而不是用暖机覆盖。
观察者效应 profiler、日志、Deep Profile、分配堆栈或硬件计数器改变被测程序时序与成本。需保存无采集基线并控制采样强度。
正确性 oracle 判断优化前后结果等价的参考实现、校验和或业务断言。漏处理工作会虚假变快,性能测试必须先关闭这个漏洞。
死代码消除 编译器/JIT 移除不可观察计算。基准必须消费结果并保持输入等价,不能把"工作被删掉"报告成算法收益。
统计显著与工程显著 前者讨论差异是否超出采样噪声,后者讨论收益是否足以影响预算并承担复杂度。统计可检出不等于值得上线。
SIMD 一条指令处理多个数据通道的执行方式。收益依赖数据连续性、循环规则、尾部、溢出、误差、硬件和后端,不保证线性加速。

Unity 专用边界

术语 精确口径
Editor / Player Editor 运行包含编辑器自身逻辑、检查和宿主开销;Player 才接近发布环境。Editor 结果不能替代目标设备构建。
Scripting Backend Unity 将脚本程序集执行/转换的后端选择,如 Mono 或 IL2CPP。它与 API Compatibility Level、Burst 和平台原生编译器是不同维度。
API Compatibility Level Unity 提供给脚本编译的参考 API 表面。它不是把 Unity 运行时切换成相同名字的桌面 .NET,也不保证所有包/平台实现相同。
Managed Stripping 构建时移除静态分析认为不可达的托管代码和元数据。反射、序列化和动态泛型路径需提供静态可达证据或精确保留规则。
[Preserve] / link.xml 向 Unity linker 表达保留意图的机制,主要处理裁剪可达性。它们不会给 IL2CPP 增加任意 JIT,也不能自动生成所有 AOT 泛型调用。
Burst 面向受支持 C# 子集和数据导向代码的编译器。Job 加 [BurstCompile] 不保证自动 SIMD,也不允许普通托管 API 任意进入 Burst 路径。
Job System 用 JobHandle 依赖和容器访问声明组织并行工作的系统。调度不是立即完成;主线程提前读写或 Dispose 会违反依赖契约。
NativeArray<T> 带原生存储、Allocator 和安全句柄语义的 Unity 容器。它不是"更快的数组"标签,必须明确所有者、Job 依赖与 Dispose 时机。
Allocator.Temp / TempJob / Persistent Unity 原生分配器的生命周期策略。名称不是建议性的注释,跨越允许期限或提前释放都属于正确性问题。
Collections Safety Checks 开发配置中帮助发现越界、并发访问和生命周期错误的检查。发布关闭检查不表示原契约消失,只是错误更难被及时诊断。
Unity fake null UnityEngine.Object 重载相等运算,用托管壳与原生对象状态表达"已销毁"。obj == null 与 obj is null 可能回答不同问题。
PlayerLoop Unity 主线程各阶段的更新循环。continuation 位于主线程不等于位于指定 Update/LateUpdate 阶段;需用具体 awaitable/调度 API 表达。
GC.Alloc Unity Profiler 在其采集边界内记录的托管分配指标。它不覆盖所有原生分配、驻留内存和生命周期问题,也会受 Development/Profiler 配置影响。
ScriptableObject 具有 Unity 资产身份和序列化规则的对象,适合作为编辑配置源。共享资产不是免费不可变运行时状态,后台线程也不应直接操作 Unity 对象。

数据结构、并发与性能

术语 精确口径
不变式 容器所有公开操作前后必须保持的性质,例如 Count <= Capacity、树的排序/颜色条件、环形队列的头尾关系。
均摊复杂度 将扩容等偶发高成本分摊到一系列操作后的平均上界。"均摊 O(1)"不表示每次操作的延迟都为常数。
线性化点 并发操作在其调用与返回之间可被视为瞬时生效的抽象时刻。可线性化不等于全局公平、无锁或等待自由。
线性化 并发历史可重排为符合实时先后约束的合法顺序历史。必须结合每个 API 的契约判定,不能仅因为使用 Interlocked 就声称线性化。
Lock-free 系统整体总有某个操作能在有限步内取得进展,不保证每个线程不饥饿。"内部有锁"、"无锁"和"线程安全"是不同维度。
Memory barrier 对内存操作的顺序和可见性施加约束的机制。C#/.NET 中应从 lock、Volatile、Interlocked等公开契约推理,不直接把 CPU 指令名当语言保证。
背压 当消费跟不上生产时,将容量压力沿协议传回上游的机制。"有界"不自动等于背压:TryWrite 失败或 Drop 模式可表示拒绝/丢弃,只有上游遵守等待/重试协议才会传导压力。
Snapshot 在某个逻辑时点提供稳定观察的数据。浅快照只复制元素/引用,不保证被引用的可变对象不再改变。
Stable sort 比较相等的元素在排序后保留原相对顺序。它与确定性输出、线程安全或原地排序是不同属性。
SSA Static Single Assignment,中间表示中每个定义版本只赋值一次的形式,便于数据流优化。它是 JIT/编译器内部表示,不是 C# 源码契约。
PGO Profile-Guided Optimization,使用采样或训练数据指导优化。动态 PGO、静态 profile 与 Unity AOT 工具链不可混为一种实现。

易混术语对照

容易混淆 正确区分
C# 版本 vs TFM vs runtime 语言版本决定语法和 lowering;TFM/reference assembly 决定可调用 API;runtime/backend 决定执行与优化。
只读 vs 不可变 只读视图只限制当前访问路径;不可变对象要求所有可观察状态都不能经其他别名改变。
Dispose vs GC Dispose 结束外部资源或租约;GC 回收不可达托管对象。二者可能协作,但没有普遍的一一对应。
Span vs Memory vs owner Span 是短期 ref-like view;Memory 是可保存 view;owner 才负责底层资源有效期和释放。
pin vs lock pin 防止对象移动;lock 建立互斥和内存可见性。pin 不防并发写,lock 也不自动提供稳定原生地址。
equality vs ordering Equality comparer 决定等价类和哈希;Comparer 决定前后顺序。排序为零不应随意当成哈希相等。
平均 O(1) vs 均摊 O(1) 平均/期望通常依赖输入或哈希分布;均摊把一个操作序列中的偶发高成本分摊,两者证明方法不同。
thread-safe vs atomic 类型可在线程安全范围内并发使用,不表示"先检查再修改"的复合业务步骤是原子的。
lock-free vs wait-free lock-free 保证系统整体进展;wait-free 还要求每个操作在有界步数完成,后者更强。
deferred vs streaming 延迟执行表示消费时才运行;流式表示可在未读完整输入前逐项产出。OrderBy 延迟但通常不流式。
snapshot vs immutable 快照固定某时点的容器观察;若只复制引用,元素对象仍可能变化。不可变要求更强的状态约束。
AOT vs NativeAOT vs IL2CPP AOT 是类别;NativeAOT 和 IL2CPP 是不同工具链。相同"无 JIT"属性不能推出相同泛型、GC、反射或 ABI。
Profiler sample vs benchmark profiler sample 定位真实场景热点;基准隔离并量化机制。二者互补,不能相互替代。
allocation vs leak 分配是创建存储;泄漏是无业务价值却仍被保留。高分配可迅速回收,低分配也可持续泄漏。

使用规则与反例

  1. 先写证据层级。 "规范要求""公开 API 契约""v8.0.0 源码观察""本机 Release 实验"不能写成同一种事实。例如,字段名 _items 是实现事实,索引越界失败才是公共契约。
  2. 复杂度必须带操作和条件。 不写"Dictionary 是 O(1)",应写"在 comparer 正确且哈希分布合理时,查找期望 O(1),退化输入最坏可达 O(n)"。
  3. 性能结论必须带环境。 不写"foreach 比 for 慢"或"Burst 快十倍",应记录静态类型、运行时/后端、构建模式、设备、输入规模和原始报告。
  4. 所有视图都追问 owner。 看到 Span、Memory、原生指针、池数组或 NativeArray 时,必须回答谁拥有、何时失效、能否跨 await/Job、谁负责 Return/Dispose。
  5. 并发 API 要写复合语义。 ConcurrentDictionary 的单次方法线程安全,不代表 ContainsKey 后索引器更新原子;应选用满足整体操作的 API 或外部同步。
  6. 取消不写成强制终止。 token 发出协作请求后,底层工作可能继续。调用方仍需观察任务、处理迟到结果并释放资源。
  7. AOT 问题先分裁剪和代码生成。 link.xml 能保留元数据/成员,却不保证任意运行时构造的闭合泛型已有可执行代码。
  8. Unity 结论至少绑定四项。 Editor 完整版本、API Compatibility Level、Mono/IL2CPP、目标平台缺一不可;涉及 Burst/Collections 时再记录包版本与 Safety Checks。
  9. 反例也要保持可编译边界。 故意错误的代码应明确标为不可编译、运行时失败或逻辑错误,不能让读者猜它属于哪一类。
  10. 术语不能替代验证。 "零分配""无锁""不可变""线程安全""原生性能"都只是待证明的具体属性,不是看到某个类型名即可附上的标签。

上一篇 :附录概要

下一篇 :附录 B:源码索引速查

相关推荐
小羊没烦恼!1 小时前
【译】利用Asp.net MVC处理文件的上传下载
开发语言·缓存·c#·word·powerpoint·.net
波力海苔夹心脆6752 小时前
C# 海康威视摄像头二次开发入门:HCNetSDK 登录、实时预览、云台控制、录像与抓图(WinForms 实战)
开发语言·windows·经验分享·tcp/ip·c#
淡海水2 小时前
16-03-C#数据结构源码-附录C-参考资源
unity·c#·游戏引擎·il2cpp
天神哥哥啊3 小时前
unity联调注意事项-安卓
android·unity·游戏引擎
天神哥哥啊3 小时前
unity联调注意事项-IOS
unity·ios·游戏引擎
asdzx673 小时前
Excel 水印方案对比:页眉图片 vs 背景图片(附 C# 实现)
c#·excel
影寂ldy3 小时前
C# TCP转串口Modbus网关终极完整版笔记(队列防抖+一问一答+帧解析+双客户端轮询)
笔记·tcp/ip·c#
可爱系程序猿14 小时前
Unity 材质预览才弹 d3dcompiler_47.dll?先分清编辑器 SDK、着色器缓存和玩家包
程序人生·3d·unity·电脑·材质
xcLeigh15 小时前
Unity基础:使用Transform控制物体缩放——localScale与lossyScale的区别
unity·游戏引擎·教程