背景
在Unity
的项目中,经常遇到各种internal的方法或者是类,但是我又需要继承或者使用它,目前我的解决方案有一下几个:
- Reflection
- InternalsVisibleToAttribute
- IgnoresAccessChecksToAttribute
- 修改dll
Reflection
反射,通过type获取其fileInfo
、MethodInfo
等
- Field
private T GetReflectionField<T>(Type superType, string fieldName)
{
var reflectFileInfo =superType.GetField(fieldName,
BindingFlags.Default | BindingFlags.Instance | BindingFlags.NonPublic);
if (reflectFileInfo == null)
{
Debug.LogError($"反射{fieldName} field失败!!");
return default;
}
var reflectData = (T)reflectFileInfo.GetValue(this);
if (reflectData == null)
{
Debug.LogError($"获取{fieldName}失败!!");
return default;
}
return reflectData;
}
反射的时候注意一下BindingFlags
,如果在Type
中能看得改成员,但是GetField
获取不到的话,自己尝试一下更换BindingFlags
- Method
private MethodInfo GetReflectionMethod(Type superType, string methodName)
{
var method = superType.GetMethod(methodName,
BindingFlags.Default | BindingFlags.Instance | BindingFlags.NonPublic);
if (method == null)
{
Debug.LogError($"反射方法{methodName}失败!!!");
return default;
}
return method;
}
其他的还有静态方法之类的,毕竟随便百度一下就能找到了,这里就不再说了!
InternalsVisibleToAttribute
我们试一下打开看看Unity.Addressables.Editor.dll
看看
我们留意到以下信息
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(/*Could not decode attribute arguments.*/)]
[assembly: InternalsVisibleTo("Unity.Addressables.Editor.Tests")]
[assembly: InternalsVisibleTo("Unity.Addressables.Tests")]
[assembly: InternalsVisibleTo("PerformanceTests.Editor")]
[assembly: AssemblyVersion("0.0.0.0")]
具有这些名称的程序集是 Unity.Addressables.Editor.dll
中的友集
。
我们先将Addressables
从Library/PackageCache
移动到Pacakges
下,然后在Addressables
中添加一个CustomAssembly.cs
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("自己的dll名称")]
编译完成后,我们从dll中看到信息多了一条
然后我们建立自己工程的dll(注意名字要和CustomAssembly
中的一致)
这样处理完成后,我们就能自己的dll中直接访问Addressables
中的各种internal
方法、类等了。
IgnoresAccessChecksToAttribute
这个方法不是我想要的!所以我放弃了,这里就只是简单把我看的link放出来!
https://qiita.com/mob-sakai/items/f3bbc0c45abc31ea7ac0
https://www.strathweb.com/2018/10/no-internalvisibleto-no-problem-bypassing-c-visibility-rules-with-roslyn/
修改dll
static void Begin()
{
string dllsDir = "Library/ScriptAssemblies";
AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly($"{dllsDir}/Unity.Addressables.Editor.dll");
var attributes = assembly.CustomAttributes;
foreach (var attribute in attributes)
{
Debug.Log(attribute.AttributeType);
}
var newAttr = assembly.MainModule.ImportReference(typeof(InternalsVisibleToAttribute).GetConstructor(new []{typeof(string)}));
var attr = new CustomAttribute(newAttr);
attr.ConstructorArguments.Add(new CustomAttributeArgument(assembly.MainModule.ImportReference(typeof(string)), "MyNewDllName"));
assembly.CustomAttributes.Add(attr);
// 为了做出区别,特意改成不一样的名字!
assembly.Write($"{dllsDir}/Unity.Addressables.Editor11111.dll");
}
使用mono.cecil
强行对已经生成的dll
写入InternalsVisibleToAttribute
,这样就和前面的InternalsVisibleToAttribute
方案一样了!