diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs
index dfef614b3..e0ef84a61 100644
--- a/Source/Engine/Engine/NativeInterop.cs
+++ b/Source/Engine/Engine/NativeInterop.cs
@@ -148,6 +148,20 @@ namespace FlaxEngine.Interop
NativeMemory.AlignedFree(ptr);
}
+ ///
+ /// Converts a delegate into a function pointer that is callable from unmanaged code via but cached delegate to prevent collecting it by GC.
+ ///
+ /// The type of delegate to convert.
+ /// The delegate to be passed to unmanaged code.
+ /// A value that can be passed to unmanaged code, which, in turn, can use it to call the underlying managed delegate.
+ public static IntPtr GetFunctionPointerForDelegate(TDelegate d) where TDelegate : notnull
+ {
+ // Example use-case: C# script runs actions via JobSystem.Dispatch which causes crash due to GC collecting Delegate object
+ ManagedHandle.Alloc(d, GCHandleType.Weak);
+
+ return Marshal.GetFunctionPointerForDelegate(d);
+ }
+
///
/// Converts array of GC Handles from native runtime to managed array.
///
diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs
index 6a9aa7669..3685cb271 100644
--- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs
+++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs
@@ -464,7 +464,7 @@ namespace Flax.Build.Bindings
return "FlaxEngine.Object.GetUnmanagedPtr({0})";
case "Function":
// delegate
- return "Marshal.GetFunctionPointerForDelegate({0})";
+ return "NativeInterop.GetFunctionPointerForDelegate({0})";
default:
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
if (apiType != null)