Mono.Cecil使用示例之使指定程序集成为UnityEditor.dll的友元程序集
Mono.Cecil是一个开源的库,使用Mono.Cecil可以非常方便的在代码中修改C#程序集。在Unity安装目录\ Editor\Data\Managed下可以找到Mono.Cecil.dll
友元程序集是一种能够访问其他程序集的 internal (C#)类型和成员的程序集。如果将程序集B指定为程序集A的友元程序集,则程序集B可以访问程序集A中所有public和internal级别的类型和成员。使用 InternalsVisibleToAttribute 特性可以为给定程序集指定一个或多个友元程序集。
将UnityEditor.dll拖到ILSpy中(可以从最后的链接中获取到ILSpy程序)
可以看到很多InternalsVisibleToAttribute 特性
Unity默认生成的Editor程序集名称为Assembly-CSharp-Editor,可以使用Mono.Cecil修改UnityEditor.dll使Assembly-CSharp-Editor成为UnityEditor.dll的友元程序集
1. 获取UnityEditor.dll的文件路径
string unityEditorPath = typeof(AssetDatabase).Assembly.ManifestModule.FullyQualifiedName;
2. 读取UnityEditor.dll程序集
AssemblyDefinition ad = AssemblyDefinition.ReadAssembly(unityEditorPath);
3. 生成InternalsVisibleToAttribute 特性
MethodBase method = typeof(InternalsVisibleToAttribute).GetConstructor(new Type[] { typeof(string) });
CustomAttribute ivt = new CustomAttribute(ad.MainModule.Import(method));
4. 设置生成的InternalsVisibleToAttribute 特性的构造函数实参为Assembly-CSharp-Editor
ivt.ConstructorArguments.Add(newCustomAttributeArgument(ad.MainModule.TypeSystem.String,"Assembly-CSharp-Editor"));
5. 为已读取的UnityEditor.dll程序集添加生成的InternalsVisibleToAttribute 特性
ad.CustomAttributes.Add(ivt);
6. 保存修改后的程序集
ad.Write(Application.dataPath +"/../UnityEditor.dll");
执行以上程序unity会报错
因为Mono.Cecil是开源的,可以直接查看源码分析错误原因,根据Log可以定位到Mono.Cecil项目中的BaseAssemblyResolver.cs文件(可以从最后的链接中获取到Mono.Cecil源码)
分析可知是因为保存程序集时会去加载要保存程序集所引用的程序集,如果在默认搜索范围内没有找到引用的程序集就会抛这个异常,查看BaseAssemblyResolver.cs文件,可以发现BaseAssemblyResolver类带有AddSearchDirectory函数,则
可以在上面的第2步骤之后增加以下代码
DefaultAssemblyResolver dar =ad.MainModule.AssemblyResolverasDefaultAssemblyResolver;
if (dar !=null)
{
dar.AddSearchDirectory(Path.GetDirectoryName(unityEditorPath));
}
保存再执行后就可以在当前工程根目录下找到UnityEditor.dll文件,拖到ILSpy中查看可以发现多了一个InternalsVisibleToAttribute 特性
关掉Unity和vs,用修改后的UnityEditor替换工程目录\Library\UnityAssemblies\UnityEditor.dll和Unity安装目录\Editor\Data\Managed\UnityEditor.dll
再打开工程就会发现可以直接在代码中获取和调用UnityEditor中为internal的类型和成员
链接:
Mono.Cecil Github
https://github.com/jbevain/cecil/
ILSpy
http://ilspy.net/