[教程] 基于 .asmref ,动态插入友元程序集新打法!!
在本文,你将学会在不侵入第三方程序集的情况下,你可以决定这个程序集对谁 Visible(成为它的友元程序集)!!!
前言
研究过不用反射访问位于其他程序集的 Internal
修饰的成员的同学们都知道 友元程序集 是实现这个需求的近乎完美的解决方案,可是这就有个问题,人家程序集凭什么对你 Visible,或者说设计之初人家怎么知道有个你呢?
常规方案
有一个常规的解决办法,那就是在这个程序集中预设几个莫须有的程序集,以后有新写的程序集想要访问这个程序集中不公开的类型,你就委屈把程序集命名成之前预设的。
Emmm... 感兴趣吗?
巧了不是,这里恰好有个活生生的示例:UnityToolchainsTrick-Example_49_Friend
如下图所示,Unity.InternalAPIEngineBridge.006
就是 UnityEditor.dll
内置的预设值友元程序集
这样一来,使用 asmdef 声明一个与 Unity.InternalAPIEngineBridge.006 同名的程序集,这个新的程序集就能访问 UnityEditor.dll
内的内部(internal)成员啦!
using UnityEditor;
namespace UnityToolchinsTrick
{
public static class PlayerSettingBind
{
public static char[] PlayerSettingDefineSplits => PlayerSettings.defineSplits;
}
}
- PlayerSettingBind 是用户自己声明的类型
- PlayerSettings.defineSplits 是 UnityEditor.dll 一个 internal 成员,但现在也能访问啦~
这种方式也太过于委曲求全了,一来不喜欢用别人的名称,太没个性;二来如果恰巧被其他人占用,那岂不是尴尬!
全新打法
铺垫这么多,下面就说说怎么实现由我来决定第三方程序集是否应该对我程序集 Visiable (友元)呢?
实现原理
- 得益于 Unity Assembly Definition 、Assembly Definition References 机制,我们可以构建一个
Assembly Definition References
文件(.asmref 文件) ,然后指定目标程序集是那个第三方程序集,这样我们就可以无侵入的为这个程序集添加脚本了。 - 我们知道,在 .Net 托管的程序集中,存在 AssemblyInfo.cs 这样一个文件,程序集就是通过这个文件中的形如:
[assembly: InternalsVisibleTo("Unity.PlasticSCM.EditorTests")]
语句知道谁是他的友元程序集,应该对谁可见! - 通过上面的 2 个机制,我们就可以很方便的让任意 Assembly Definition 文件(.asmdef 文件)定义的第三方程序集对我们的程序集可见啦!
实操演练
- 使用 A.asmdef 和 B.asmdef 文件定义 2 个新的程序集 A.dll 和 B.dll
- 在程序集 A 中随意写上一些内部和公开的成员
- 在程序集 B 所在资产目录中新建 Internal 文件夹,构建 .asmref 文件并指向 A.asmdef
- 在这个 Internal 文件夹中构建 AssemblyInfo.cs 并写下如下内容:
[assembly: InternalsVisibleTo("B")]
得到的资产结构如下:
-
在程序集 B 中新建测试脚本,尝试访问程序集 A 中的 内部成员
-
你会发现在不修改程序集 A 的任意资产情况下,就实现了程序集 B中访问程序集 A 内部成员!
Before | After |
-
使用 ILSpy 反编译观察可见我们插入的对程序集 B 可见的相关信息:
本文配套演示工程 Friend-Assembly-By-asmref
写到最后
- 这种方法也有些限制,比如只能用在使用
Assembly Definition
定义的程序集; - 程序集中已经存在 AssemblyInfo.cs 不会有任何问题,编译器会自动整合的哦!
- 当然,我也是偶然看到这种用法,觉得新奇还有用便行文记之,如果觉得有趣,留下你的赞吧!
-
如果你关注了 Unity 最新的多语言插件,你就会发现这种用法了
版权所有,转载请注明出处!