unitycsharp

[教程] 基于 .asmref ,动态插入友元程序集新打法!!

2024-06-14  本文已影响0人  雨落随风

在本文,你将学会在不侵入第三方程序集的情况下,你可以决定这个程序集对谁 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;
    }
}

这种方式也太过于委曲求全了,一来不喜欢用别人的名称,太没个性;二来如果恰巧被其他人占用,那岂不是尴尬!

全新打法

铺垫这么多,下面就说说怎么实现由我来决定第三方程序集是否应该对我程序集 Visiable (友元)呢?

实现原理

  1. 得益于 Unity Assembly Definition 、Assembly Definition References 机制,我们可以构建一个 Assembly Definition References 文件(.asmref 文件) ,然后指定目标程序集是那个第三方程序集,这样我们就可以无侵入的为这个程序集添加脚本了。
  2. 我们知道,在 .Net 托管的程序集中,存在 AssemblyInfo.cs 这样一个文件,程序集就是通过这个文件中的形如:[assembly: InternalsVisibleTo("Unity.PlasticSCM.EditorTests")] 语句知道谁是他的友元程序集,应该对谁可见!
  3. 通过上面的 2 个机制,我们就可以很方便的让任意 Assembly Definition 文件(.asmdef 文件)定义的第三方程序集对我们的程序集可见啦!

实操演练

  1. 使用 A.asmdef 和 B.asmdef 文件定义 2 个新的程序集 A.dll 和 B.dll
  2. 在程序集 A 中随意写上一些内部和公开的成员
  3. 在程序集 B 所在资产目录中新建 Internal 文件夹,构建 .asmref 文件并指向 A.asmdef
  4. 在这个 Internal 文件夹中构建 AssemblyInfo.cs 并写下如下内容:
[assembly: InternalsVisibleTo("B")]

得到的资产结构如下:


  1. 在程序集 B 中新建测试脚本,尝试访问程序集 A 中的 内部成员

  2. 你会发现在不修改程序集 A 的任意资产情况下,就实现了程序集 B中访问程序集 A 内部成员!

Before After
  1. 使用 ILSpy 反编译观察可见我们插入的对程序集 B 可见的相关信息:


本文配套演示工程 Friend-Assembly-By-asmref

写到最后

  1. 这种方法也有些限制,比如只能用在使用 Assembly Definition 定义的程序集;
  2. 程序集中已经存在 AssemblyInfo.cs 不会有任何问题,编译器会自动整合的哦!
  3. 当然,我也是偶然看到这种用法,觉得新奇还有用便行文记之,如果觉得有趣,留下你的赞吧!
  4. 如果你关注了 Unity 最新的多语言插件,你就会发现这种用法了


版权所有,转载请注明出处!

上一篇 下一篇

猜你喜欢

热点阅读