Unity 中自定义程序集的使用以及程序集的划分

官方说明

先引用一下官方自己对自定义程序集的解释, 官方手册中的说明已经非常详细了, 下面是手册链接

Assembly

手册上已经有的我就不重复赘述了, 说明一下我在使用过程中的一些经验

程序集的划分

程序集划分为: 预定义程序集预编译程序集自定义程序集

预定义程序集 (Predefined assembly)

预定义程序集指的是 Unity 引擎自己预先定义好的一些程序集, 比如项目代码会生成的 Assembly-CSharpAssembly-CSharp-Editor, 还有引擎程序集, 比如 UnityEngine, UnityEditor

预编译程序集 (Precompiled assembly)

手册原文解释

A precompiled assembly is a library compiled outside your Unity Project.

很字面意思, 即在 Unity 项目外预先编译好的程序集, 例如 DoTween.dll

自定义程序集 (Project assembly)

只有使用 自定义程序集文件 所定义的程序集才是自定义程序集, 在官方手册中被称为 Project assembly

为什么要使用自定义程序集

🐔原因一 : 可以非常有效且明确地划分代码之间的依赖关系

不使用自定义程序集划分, 代码会被编译到 Assembly-CSharp.dll 中, 所有的代码都在一个程序集中 (不考虑编辑器代码, 不要鸡蛋里挑骨头), 那么所有的代码之间都可以相互引用, 并且没有任何限制, 在如今 IDE 都可以自动补全命名空间的情况下, 使用命名空间来区分完全不现实, 命名空间目前基本就一个作用了, 让类的命名不再那么小心翼翼, 可以使用重名类, 不在一个空间下就行了

使用自定义程序集来手动划分代码所属程序集, 解开 游戏框架 - 逻辑模块 - 插件 - 开发库 之间的耦合; 同时因为程序集之间如果不明确引用的话, 在代码中是无法使用的, 可以有效防止新手程序员乱写, 这种规范性问题如果仅仅靠程序员的能力来自觉维护是不可能的

🦄原因二 : 方便实现逻辑的热更新

可以手动划分出热更程序集, 用于热更新

👽原因三 : 开发时加快代码编译速度

这个是手册中就提到的事情, 通过有效划分程序集, 可以实现当修改了上层程序集的代码时, 编译时只会重新编译代码所属的程序集, 节省编译时间, 当然这一点的实现需要合理的程序集划分, 因为当程序集重新编译时, 引用了此程序集的程序集也需要重新编译

以下面的图为例, 当仅仅修改了 main.dll 中的代码时, 那么只有 main.dll 会进行重新编译

但是如果修改了 Library.dll 中的代码, 那么 Main.dll, Stuff.dll, Library.dll 三个程序集都需要重新编译, 因此合理的程序集划分非常重要

程序集划分

如何划分程序集

程序集的划分要参考上面所说的 3 个目的去划分, 都需要结合实际项目说明, 这里举例子的话就只说明一些最基本的划分底限, 也就是绝对需要遵守的规则

  • 不使用 Assembly-CSharp 程序集

这里的意思并不是说要删除掉这个程序集, 而是需要控制项目中的代码全部使用自定义程序集来划分, 任何项目代码都不许被编译到主程序集中.

这里的项目代码指的也只是项目开发中自己所编写的代码, 像很多插件库, 他们一般有自己的程序集划分, 但是也可能没有啊, 这部分代码并不是我们自己开发的, 我们可以自己去给他划分程序集, 也可以不划分, 可以大致参考手册图片中的划分方式划分即可. (当然这个图也就仅供参考了)

  • 库, 框架, 工具集, 逻辑模块都需要单独设立程序集

开发时使用的开发库需要有自己的程序集, 包括框架, 工具集, 各个逻辑模块都需要有自己的程序集, 具体的划分就需要按照项目自己制定了

程序集文件的选项解释

对 Unity 中程序集文件各个选项的进一步解释, 补充手册的不足, 下文中的 此程序集 都是指这个选项所归属的程序集

Allow 'unsafe' Code

字面意思, 允许使用 'unsafe', 不解释, 用到就勾, 用不到就不勾.

Allow 'unsafe' Code : 按需设置, 基本用不到

Auto Referenced

这个是手册里面的解释

Specify whether the predefined assemblies should reference this Project assembly.

新手可能看起来有点晕, 我直接说明效果, 勾选选项后, 在 Assembly-CSharp.dll 中的代码才能引用此程序集中的代码, 不勾选的话是无法引用此程序集代码的

这对于一些老项目而言非常有用, 因为老项目的代码基本都是在 Assembly-CSharp.dll 中, 这时候独立出来的一些自定义程序集就必须都勾选此选项, 让主程序集能够引用自己.

而新项目如果根据上面的程序集划分准则划分程序集的话, 则不要勾选此选项, 而是在需要引用此程序集的地方手动设置引用

Auto Referenced : 旧项目推荐勾选, 方便省事

Auto Referenced : 新项目一律不勾选

No Engine References

字面意思, 如果程序集中的代码完全不需要使用 UnityEditorUnityEngine 等引擎相关代码, 那就可以勾选

No Engine References : 按需设置

Root Namespace

设置根命名空间的, 这个选项极其具有误导性, 上面的选项都是优化程序集设置的, 设置后或多或少都会对程序集造成影响, 但是这个选项不会, 是的, 你没有看错, 这个选项不会对程序集造成任何影响! 这个选项不会对程序集造成任何影响! 这个选项不会对程序集造成任何影响!

这个选项的作用只是为了方便程序编写代码, 设置此选项后, 在此目录下新建代码文件, Unity 引擎会自动在代码中生成命名空间的代码, 仅此而已.

另外说明一下, 这个只是一个代码自动生成的辅助功能, 不要以为这里设置了命名空间, 代码中就不需要写了, 不是的, 代码中自动生成的那行 namespace 可不能删除哦.

最后再说一下, 只有通过 Unity 创建代码文件的时候才会生效, 在 IDE 中此设置并没有效果!

Root Namespace : 无所谓, 看你心情

Assembly Definition References

这个列表即设置此程序集需要引用的其他程序集, 包括预定义程序集其他自定义程序集, 而预编译程序集的引用不在这里设置, 而是下面的 Override References 中设置

Assembly Definition Referencess : 按需设置

Override References

这个是对预编译程序集 (Precompiled assembly) 引用的设置, 不勾选的话, 此程序集会引用全部的预编译程序集, 勾选后则需要手动设置

Override References : 旧项目推荐不勾选, 方便省事

Override References : 新项目一律勾选

Platforms

字面意思, 程序集的平台兼容性设置, 可以设置程序集仅在哪些平台上编译

Platforms : 按需设置

Define Constraints

这个也很好理解, 宏控制, 代码编写中也经常使用类似的功能, 很有用.

比如你写了一个库, 这个库可能只有在满足了某种条件下才能使用, 此时就可以使用宏来控制此程序集是否编译, 如果项目中没有此宏, 程序集是不会编译的, 可以放心大胆的放到项目中

Define Constraints : 按需设置

循环引用

设置程序集引用关系的时候, 一定要避循环引用, 即 A 引用 B, B 引用 A

前面说过, 程序集重新编译时, 引用此程序集的程序集也会被触发重新编译, 那么 A 重新编译时, 触发了 B 重新编译, 然后 B 的重新编译又触发了 A 重新编译... 编译器: ? ? ? 你 TM 在搞我 ? ? ?

不过设置了循环引用后, 引擎也会报错的, 所以注意一下就好

设置举例

程序集划分

程序集划分