InjectFix icon indicating copy to clipboard operation
InjectFix copied to clipboard

带默认值回调参数的函数热更报错

Open 8Avalon8 opened this issue 5 years ago • 5 comments

项目中某个函数中调用了一个带默认值参数的函数,其中一个参数是Action,代码示意如下 public class A{ public B b; public void MethodA(){ ...... b.MethodB(()=>{ // somecode }); } }

public class B{ public void MethodB(Action callback = null, bool isTrue = false){ // somecode } }

最后会报下面的错误 检查了一下MethodB没有重载函数

异常可能未捕获: ArgumentException: method arguments are incompatible $$ System.Delegate.CreateDelegate (System.Type type, System.Object firstArgument, System.Reflection.MethodInfo method, Boolean throwOnBindFailure) $$ System.Delegate.CreateDelegate (System.Type type, System.Object firstArgument, System.Reflection.MethodInfo method) $$ IFix.Core.Utils.TryAdapterToDelegate (System.Object obj, System.Type delegateType, System.String perfix) $$ IFix.WrappersManagerImpl.CreateDelegate (System.Type type, Int32 id, System.Object anon) $$ IFix.Core.VirtualMachine.Execute (IFix.Core.Instruction* pc, IFix.Core.Value* argumentBase, System.Object[] managedStack, IFix.Core.Value* evaluationStackBase, Int32 argsCount, Int32 methodIndex, Int32 refCount, IFix.Core.Value** topWriteBack) $$ IFix.Core.VirtualMachine.Execute (Int32 methodIndex, Call& call, Int32 argsCount, Int32 refCount) $$ IFix.ILFixDynamicMethodWrapper.__Gen_Wrap_213 (System.Object P0, System.Object P1, System.Object P2, System.Object P3, Int32 P4, System.Object P5, System.Object P6)

8Avalon8 avatar Nov 09 '20 09:11 8Avalon8

之前线上的时候还有一个奇怪的问题,两处代码完全没有关联,但是当前者执行之后,后者再去执行就会报错,反过来,先执行后者在执行前者也会报错,没记错的话报错就是method arguments are incompatible(时间有点久不太确定了),是否有可能是因为做了什么缓存,两者有调同样的delegate,但被错误的归于一种了?所以第二次调用的时候使用的是错误的method?

8Avalon8 avatar Nov 09 '20 09:11 8Avalon8

按道理默认只是个编译器语法糖,编译完后都是编译器帮你填写了参数,和这报错应该没关吧

chexiongsheng avatar Nov 11 '20 08:11 chexiongsheng

主要是现象上如此,然后稍微看了下Ifix的代码报错处 在create delegate的时候是从缓存里拿出来的,是否有可能是项目某个地方另外一个函数create的delegate放在缓存后,后续的createdelegate错误的从缓存里拿了一个实际上不匹配的东西,然后导致了报错呢?

public static Delegate TryAdapterToDelegate(object obj, Type delegateType, string perfix) { MethodInfo method; if (!delegateAdptCache.TryGetValue(delegateType, out method)) { MethodInfo delegateMethod = delegateType.GetMethod("Invoke"); var methods = obj.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); for (int i = 0; i < methods.Length; i++) { if (methods[i].Name.StartsWith(perfix) && IsAssignable(delegateMethod, methods[i])) { method = methods[i]; delegateAdptCache[delegateType] = method; } } } if (method == null) { return null; } else { return Delegate.CreateDelegate(delegateType, obj, method); } }

//适配器的缓存,如果不做缓存,每次都调用IsAssignable一个个的取匹配会非常慢 static Dictionary<Type, MethodInfo> delegateAdptCache = new Dictionary<Type, MethodInfo>();

8Avalon8 avatar Nov 11 '20 08:11 8Avalon8

同一个Delegate的类型,第一次匹配过后且创建成功,第二次就不会失败。要失败应该也是第一次

chexiongsheng avatar Nov 11 '20 09:11 chexiongsheng

有简单的必现代码,可以贴一个

chexiongsheng avatar Nov 11 '20 09:11 chexiongsheng