using System.Collections.Concurrent; using System.Reflection; using AyCode.Services.SignalRs; namespace AyCode.Models.Server.DynamicMethods; /// /// Registry for dynamic method lookups with lazy initialization. /// Caches method metadata statically (by messageTag), resolves instances per-request. /// /// The attribute type used to mark methods (e.g., SignalRAttribute) public class AcDynamicMethodRegistry where TAttribute : TagAttribute { /// /// Statikus cache: messageTag → (DeclaringType, MethodInfo) /// A reflection eredménye, nem változik runtime-ban. /// null érték = már kerestük, de nem találtuk. /// private static readonly ConcurrentDictionary Method)?> _methodLookupCache = new(); /// /// Instance array - NEM statikus, request/Hub-specifikus. /// Array is faster than List for small fixed-size collections (2-5 elements). /// private object[] _instances = []; private int _count; /// /// Gets or sets the capacity of the instance array. /// Set this before calling Register() to avoid allocations. /// public int CahcheSizeCapacity { get => _instances.Length; set => _instances = new object[value]; } /// /// Registers an instance for method lookup. /// No reflection happens here - just stores the instance reference. /// public void Register(object instance) { if (_count >= _instances.Length) { // CahcheSizeCapacity not set or exceeded - resize var newSize = _instances.Length == 0 ? 4 : _instances.Length * 2; Array.Resize(ref _instances, newSize); } _instances[_count++] = instance; } /// /// Finds the method and instance for a given messageTag. /// Uses cached lookup when possible, falls back to lazy search. /// public (object Instance, AcMethodInfoModel Method)? GetMethodByMessageTag(int messageTag) { // 1. Check cache first if (_methodLookupCache.TryGetValue(messageTag, out var cached)) { if (cached == null) return null; // Already searched, not found // Find the instance of the cached type var instance = FindInstanceByType(cached.Value.DeclaringType); if (instance != null) return (instance, cached.Value.Method); } // 2. Lazy search through registered instances for (var i = 0; i < _count; i++) { var instance = _instances[i]; var type = instance.GetType(); // Search methods with TAttribute foreach (var methodInfo in type.GetMethods()) { if (methodInfo.GetCustomAttribute(typeof(TAttribute)) is not TAttribute attribute) continue; if (attribute.MessageTag == messageTag) { var method = new AcMethodInfoModel(attribute, methodInfo); _methodLookupCache[messageTag] = (type, method); return (instance, method); } } } // 3. Not found - cache this result too _methodLookupCache[messageTag] = null; return null; } /// /// Finds an instance by its type from the registered instances. /// private object? FindInstanceByType(Type type) { for (var i = 0; i < _count; i++) { var instance = _instances[i]; if (instance.GetType() == type) return instance; } return null; } /// /// Gets the number of registered instances. /// public int Count => _count; }