labbbirder / UnityInjection

Unity DLL注入,支持全平台,支持Mono和IL2CPP,支持注入引擎和用户DLL。可以实现AOP、装饰器等功能
MIT License
115 stars 14 forks source link

[异常] (装饰器) 函数参数泛型自带 UnityEngine.Object 抛异常 #4

Closed xinansky closed 4 months ago

xinansky commented 4 months ago

示例: 函数A:public static void LoadSubAssets(string location, Action<Object[]> cb) 函数B:public static void LoadSubAssets(string location, Type type, Action<Object[]> cb) 函数C:public static void LoadSubAssets(string location, Action<TObject[]> cb) where TObject : Object 给函数B加上自定义装饰器实现了 DecoratorAttribute 的属性 并开始编译 会抛出异常 信息如下 Exception: Cannot find Method LoadSubAssets in Type xxxx_class 报错库函数: InjectHelper.cs FindMethod td.Methods.FirstOrDefault(m => m.GetSignature() == methodSignature) == null Unity版本 2022.3.8f1

xinansky commented 4 months ago

原因已经找到 MethodBase.GetSignature函数与MethodDefinition.GetSignature函数判断值出现不一致 目前使用 (MethodDefinition)a.MetadataToken.ToInt32() 和 (MethodBase)b.MetadataToken 作为判断值

internal static MethodReference FindMethod(this TypeDefinition td, MethodBase methodSignature)
{
      return (from method in td.Methods
            where method.MetadataToken.ToInt32() == methodSignature.MetadataToken
            select td.Module?.ImportReference(method)).FirstOrDefault();
}
labbbirder commented 4 months ago

@xinansky 感谢fix,下个版本修正

labbbirder commented 4 months ago

原因已经找到 MethodBase.GetSignature函数与MethodDefinition.GetSignature函数判断值出现不一致 目前使用 (MethodDefinition)a.MetadataToken.ToInt32() 和 (MethodBase)b.MetadataToken 作为判断值

internal static MethodReference FindMethod(this TypeDefinition td, MethodBase methodSignature)
{
      return (from method in td.Methods
            where method.MetadataToken.ToInt32() == methodSignature.MetadataToken
            select td.Module?.ImportReference(method)).FirstOrDefault();
}

MetadataToken是一种很聪明的做法,但新的修复还是使用签名的方式实现,原因有下:

  1. 考虑到UnityInjection在注入时加载的Assembly和目标Assembly虽然AssemblyName相同,但有时不是同一个(通常是那些有变种的预编译程序集Precompiled Assemblies with variants),对于这种情况两者的MetadataToken很有可能是不一致的。当然,这种不一致的情况只发生在Runtime,Editor下是无法察觉的。
  2. 签名的验证只发生在Editor构建时,不对运行时产生负载。