| | | 1 | | using System.Diagnostics.CodeAnalysis; |
| | | 2 | | using System.Reflection; |
| | | 3 | | |
| | | 4 | | namespace NexusLabs.Needlr.Injection.Reflection.TypeFilterers; |
| | | 5 | | |
| | | 6 | | /// <summary> |
| | | 7 | | /// Type filterer that uses runtime reflection to analyze constructors. |
| | | 8 | | /// </summary> |
| | | 9 | | /// <remarks> |
| | | 10 | | /// This filterer is not compatible with NativeAOT or trimming. For AOT scenarios, |
| | | 11 | | /// use GeneratedTypeFilterer from NexusLabs.Needlr.Injection.SourceGen with the Needlr source generator instead. |
| | | 12 | | /// </remarks> |
| | | 13 | | [RequiresUnreferencedCode("ReflectionTypeFilterer uses reflection to analyze constructors. Use GeneratedTypeFilterer for |
| | | 14 | | public sealed class ReflectionTypeFilterer : ITypeFilterer |
| | | 15 | | { |
| | | 16 | | /// <inheritdoc /> |
| | | 17 | | public bool IsInjectableScopedType(Type type) |
| | 191264 | 18 | | => IsInjectableType(type) && type.GetCustomAttribute<ScopedAttribute>(inherit: true) is not null; |
| | | 19 | | |
| | | 20 | | /// <inheritdoc /> |
| | | 21 | | public bool IsInjectableTransientType(Type type) |
| | 191910 | 22 | | => IsInjectableType(type) && type.GetCustomAttribute<TransientAttribute>(inherit: true) is not null; |
| | | 23 | | |
| | | 24 | | /// <inheritdoc /> |
| | | 25 | | public bool IsInjectableSingletonType(Type type) |
| | | 26 | | { |
| | 288991 | 27 | | if (!IsInjectableType(type)) |
| | 189202 | 28 | | return false; |
| | | 29 | | |
| | | 30 | | // Explicit [Singleton] attribute or no lifetime attribute (default) |
| | 99789 | 31 | | var hasSingleton = type.GetCustomAttribute<SingletonAttribute>(inherit: true) is not null; |
| | 99789 | 32 | | var hasScoped = type.GetCustomAttribute<ScopedAttribute>(inherit: true) is not null; |
| | 99789 | 33 | | var hasTransient = type.GetCustomAttribute<TransientAttribute>(inherit: true) is not null; |
| | | 34 | | |
| | 99789 | 35 | | return hasSingleton || (!hasScoped && !hasTransient); |
| | | 36 | | } |
| | | 37 | | |
| | | 38 | | private static bool IsInjectableType(Type type) |
| | | 39 | | { |
| | 672165 | 40 | | if (!TypeFiltering.IsConcreteType(type)) |
| | 561563 | 41 | | return false; |
| | | 42 | | |
| | 110602 | 43 | | if (type.GetCustomAttribute<DoNotInjectAttribute>(inherit: true) is not null) |
| | 25 | 44 | | return false; |
| | | 45 | | |
| | 110577 | 46 | | var ctors = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); |
| | 339018 | 47 | | foreach (var ctor in ctors) |
| | | 48 | | { |
| | 111231 | 49 | | var parameters = ctor.GetParameters(); |
| | 111231 | 50 | | if (parameters.Length == 0) |
| | 95535 | 51 | | return true; |
| | | 52 | | |
| | 15696 | 53 | | if (parameters.Length == 1 && parameters[0].ParameterType == type) |
| | 25 | 54 | | return false; |
| | | 55 | | |
| | 15671 | 56 | | if (parameters.All(p => |
| | 38264 | 57 | | !p.ParameterType.IsAssignableTo(typeof(MulticastDelegate)) && |
| | 38264 | 58 | | !p.ParameterType.IsValueType && |
| | 38264 | 59 | | !p.ParameterType.Equals(typeof(string)) && |
| | 38264 | 60 | | !p.ParameterType.IsPrimitive && |
| | 38264 | 61 | | (p.ParameterType.IsClass || |
| | 38264 | 62 | | p.ParameterType.IsInterface))) |
| | | 63 | | { |
| | 9038 | 64 | | return true; |
| | | 65 | | } |
| | | 66 | | } |
| | | 67 | | |
| | 5979 | 68 | | return false; |
| | | 69 | | } |
| | | 70 | | } |