#nullable enable using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace ShrinkNetwork { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public sealed class ShrinkNetworkMessageRegistryAttribute : Attribute { public ShrinkNetworkMessageRegistryAttribute(params Type[] messageTypes) { MessageTypes = messageTypes ?? Array.Empty(); } public Type[] MessageTypes { get; } } [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] public sealed class ShrinkNetworkStaticSubscriberRegistryAttribute : Attribute { public ShrinkNetworkStaticSubscriberRegistryAttribute(params Type[] subscriberTypes) { SubscriberTypes = subscriberTypes ?? Array.Empty(); } public Type[] SubscriberTypes { get; } } internal static class ShrinkNetworkGeneratedRegistry { public static IReadOnlyList GetAttributedMessageTypes() => GetAssemblyRegisteredTypes(attribute => attribute.MessageTypes); public static IReadOnlyList GetStaticSubscriberTypes() => GetAssemblyRegisteredTypes(attribute => attribute.SubscriberTypes); public static void RegisterAll(ShrinkNetworkService service) { if (service == null) throw new ArgumentNullException(nameof(service)); ShrinkNetworkRegHelper.RegisterAttributedMessages(service, GetAttributedMessageTypes()); ShrinkNetworkRegHelper.RegisterStaticHandlers(service, GetStaticSubscriberTypes()); } private static IReadOnlyList GetAssemblyRegisteredTypes(Func selector) where TAttribute : Attribute { var types = new List(); var seen = new HashSet(); foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { object[] attributes; try { attributes = assembly.GetCustomAttributes(typeof(TAttribute), false); } catch { continue; } foreach (var attribute in attributes.OfType()) { foreach (var registeredType in selector(attribute) ?? Array.Empty()) { if (registeredType == null || !seen.Add(registeredType)) continue; types.Add(registeredType); } } } return types; } } }