diff --git a/src/Foundation/NSObject2.cs b/src/Foundation/NSObject2.cs index 02297f793693..299b32ec8468 100644 --- a/src/Foundation/NSObject2.cs +++ b/src/Foundation/NSObject2.cs @@ -475,6 +475,34 @@ public virtual bool ConformsToProtocol (NativeHandle protocol) if (!Runtime.DynamicRegistrationSupported) return false; + // the linker/trimmer will remove the following code if the dynamic registrar is removed from the app + var classHandle = ClassHandle; + lock (Runtime.protocol_cache) { +#if NET + ref var map = ref CollectionsMarshal.GetValueRefOrAddDefault (Runtime.protocol_cache, classHandle, out var exists); + if (!exists) + map = new (); + ref var result = ref CollectionsMarshal.GetValueRefOrAddDefault (map, protocol, out exists); + if (!exists) + result = DynamicConformsToProtocol (protocol); +#else + bool new_map = false; + if (!Runtime.protocol_cache.TryGetValue (classHandle, out var map)) { + map = new (); + new_map = true; + Runtime.protocol_cache.Add (classHandle, map); + } + if (new_map || !map.TryGetValue (protocol, out var result)) { + result = DynamicConformsToProtocol (protocol); + map.Add (protocol, result); + } +#endif + return result; + } + } + + bool DynamicConformsToProtocol (NativeHandle protocol) + { object [] adoptedProtocols = GetType ().GetCustomAttributes (typeof (AdoptsAttribute), true); foreach (AdoptsAttribute adopts in adoptedProtocols){ if (adopts.ProtocolHandle == protocol) diff --git a/src/ObjCRuntime/Runtime.cs b/src/ObjCRuntime/Runtime.cs index 2e65eab6e1bd..bfcebcaac387 100644 --- a/src/ObjCRuntime/Runtime.cs +++ b/src/ObjCRuntime/Runtime.cs @@ -35,6 +35,7 @@ public partial class Runtime { static Dictionary block_to_delegate_cache; static Dictionary intptr_ctor_cache; static Dictionary intptr_bool_ctor_cache; + internal static Dictionary> protocol_cache; static List delegates; static List assemblies; @@ -280,8 +281,10 @@ unsafe static void Initialize (InitializationOptions* options) NSObjectClass = NSObject.Initialize (); - if (DynamicRegistrationSupported) + if (DynamicRegistrationSupported) { Registrar = new DynamicRegistrar (); + protocol_cache = new Dictionary> (IntPtrEqualityComparer); + } RegisterDelegates (options); Class.Initialize (options); #if !NET