diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index fc04d9668..026f54fec 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -1331,39 +1331,50 @@ namespace FlaxEngine.Interop // Skip using in-built delegate for value types (eg. Transform) to properly handle instance value passing to method if (invokeDelegate == null && !method.DeclaringType.IsValueType) { - List methodTypes = new List(); - if (!method.IsStatic) - methodTypes.Add(method.DeclaringType); - if (returnType != typeof(void)) - methodTypes.Add(returnType); - methodTypes.AddRange(parameterTypes); - - List genericParamTypes = new List(); - foreach (var type in methodTypes) + // Thread-safe creation + lock (typeCache) { - if (type.IsByRef) - genericParamTypes.Add(type.GetElementType()); - else if (type.IsPointer) - genericParamTypes.Add(typeof(IntPtr)); - else - genericParamTypes.Add(type); - } - - string invokerTypeName = $"{typeof(Invoker).FullName}+Invoker{(method.IsStatic ? "Static" : "")}{(returnType != typeof(void) ? "Ret" : "NoRet")}{parameterTypes.Length}{(genericParamTypes.Count > 0 ? "`" + genericParamTypes.Count : "")}"; - Type invokerType = Type.GetType(invokerTypeName); - if (invokerType != null) - { - if (genericParamTypes.Count != 0) - invokerType = invokerType.MakeGenericType(genericParamTypes.ToArray()); - invokeDelegate = invokerType.GetMethod(nameof(Invoker.InvokerStaticNoRet0.MarshalAndInvoke), BindingFlags.Static | BindingFlags.NonPublic).CreateDelegate(); - delegInvoke = invokerType.GetMethod(nameof(Invoker.InvokerStaticNoRet0.CreateDelegate), BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[] { method }); + if (invokeDelegate == null) + { + TryCreateDelegate(); + } } } - outDeleg = invokeDelegate; outDelegInvoke = delegInvoke; return outDeleg != null; } + + private void TryCreateDelegate() + { + var methodTypes = new List(); + if (!method.IsStatic) + methodTypes.Add(method.DeclaringType); + if (returnType != typeof(void)) + methodTypes.Add(returnType); + methodTypes.AddRange(parameterTypes); + + var genericParamTypes = new List(); + foreach (var type in methodTypes) + { + if (type.IsByRef) + genericParamTypes.Add(type.GetElementType()); + else if (type.IsPointer) + genericParamTypes.Add(typeof(IntPtr)); + else + genericParamTypes.Add(type); + } + + string invokerTypeName = $"{typeof(Invoker).FullName}+Invoker{(method.IsStatic ? "Static" : "")}{(returnType != typeof(void) ? "Ret" : "NoRet")}{parameterTypes.Length}{(genericParamTypes.Count > 0 ? "`" + genericParamTypes.Count : "")}"; + Type invokerType = Type.GetType(invokerTypeName); + if (invokerType != null) + { + if (genericParamTypes.Count != 0) + invokerType = invokerType.MakeGenericType(genericParamTypes.ToArray()); + delegInvoke = invokerType.GetMethod(nameof(Invoker.InvokerStaticNoRet0.CreateDelegate), BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[] { method }); + invokeDelegate = invokerType.GetMethod(nameof(Invoker.InvokerStaticNoRet0.MarshalAndInvoke), BindingFlags.Static | BindingFlags.NonPublic).CreateDelegate(); + } + } #endif }