< Summary

Information
Class: Pozitron.QuerySpecification.TypeDiscovery
Assembly: Pozitron.QuerySpecification
File(s): /home/runner/work/QuerySpecification/QuerySpecification/src/QuerySpecification/Internals/TypeDiscovery.cs
Tag: 74_17335419374
Line coverage
87%
Covered lines: 94
Uncovered lines: 14
Coverable lines: 108
Total lines: 156
Line coverage: 87%
Branch coverage
82%
Covered branches: 46
Total branches: 56
Branch coverage: 82.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()62.5%242485.07%
GetMemoryEvaluators()100%11100%
GetEvaluators()100%11100%
GetValidators()100%11100%
GetInstancesOf()100%11100%
GetInstancesOf(...)93.75%323288.88%

File(s)

/home/runner/work/QuerySpecification/QuerySpecification/src/QuerySpecification/Internals/TypeDiscovery.cs

#LineLine coverage
 1using System.Diagnostics;
 2using System.Reflection;
 3
 4namespace Pozitron.QuerySpecification;
 5
 6internal static class TypeDiscovery
 7{
 38    private static readonly Lazy<bool> _isDebugBuild = new(
 39        () =>
 310        {
 011            var debugAttribute = Assembly
 012                .GetEntryAssembly()?
 013                .GetCustomAttributes<DebuggableAttribute>()
 014                .FirstOrDefault();
 315
 016            return debugAttribute is not null
 017                && (debugAttribute.DebuggingFlags & DebuggableAttribute.DebuggingModes.Default) == DebuggableAttribute.D
 318        },
 319        LazyThreadSafetyMode.ExecutionAndPublication);
 20
 321    private static readonly Lazy<Assembly[]> _loadedAssemblies = new(
 322        () =>
 323        {
 324            try
 325            {
 326                return AppDomain.CurrentDomain
 327                    .GetAssemblies()
 328                    .Where(a =>
 26229                        a.IsDynamic == false &&
 26230                        a.FullName != null &&
 26231                        !a.FullName.StartsWith("System", StringComparison.OrdinalIgnoreCase) &&
 26232                        !a.FullName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase) &&
 26233                        !a.FullName.StartsWith("netstandard", StringComparison.OrdinalIgnoreCase) &&
 26234                        !a.FullName.StartsWith("Windows", StringComparison.OrdinalIgnoreCase)
 335                    )
 336                    .ToArray();
 337            }
 038            catch (Exception ex)
 339            {
 040                if (_isDebugBuild.Value)
 341                {
 042                    throw new SpecAutoDiscoveryException(ex);
 343                }
 044                return [];
 345            }
 346        },
 347        LazyThreadSafetyMode.ExecutionAndPublication);
 48
 349    private static readonly Lazy<string> _autoDiscoveryValue = new(
 350        () =>
 351        {
 352            var entryAssembly = Assembly.GetEntryAssembly();
 353            var attr = entryAssembly?.GetCustomAttributes<SpecAutoDiscoveryAttribute>().FirstOrDefault();
 354            if (attr is not null) return attr.Value;
 355
 8356            foreach (var asm in _loadedAssemblies.Value)
 357            {
 3958                attr = asm.GetCustomAttributes<SpecAutoDiscoveryAttribute>().FirstOrDefault();
 4059                if (attr is not null) return attr.Value;
 360            }
 361
 262            return string.Empty;
 363        },
 364        LazyThreadSafetyMode.ExecutionAndPublication);
 65
 366    private static readonly Lazy<bool> _isAutoDiscoveryEnabled = new(
 367        () => _autoDiscoveryValue.Value.Equals("enable", StringComparison.OrdinalIgnoreCase),
 368        LazyThreadSafetyMode.ExecutionAndPublication);
 69
 370    private static readonly Lazy<List<IEvaluator>> _evaluators = new(
 271        () => GetInstancesOf<IEvaluator, DiscoveryAttribute>(),
 372        LazyThreadSafetyMode.ExecutionAndPublication);
 73
 374    private static readonly Lazy<List<IMemoryEvaluator>> _memoryEvaluators = new(
 275        () => GetInstancesOf<IMemoryEvaluator, DiscoveryAttribute>(),
 376        LazyThreadSafetyMode.ExecutionAndPublication);
 77
 378    private static readonly Lazy<List<IValidator>> _validators = new(
 279        () => GetInstancesOf<IValidator, DiscoveryAttribute>(),
 380        LazyThreadSafetyMode.ExecutionAndPublication);
 81
 82
 1983    internal static bool IsAutoDiscoveryEnabled => _isAutoDiscoveryEnabled.Value;
 484    internal static List<IMemoryEvaluator> GetMemoryEvaluators() => _memoryEvaluators.Value.ToList();
 485    internal static List<IEvaluator> GetEvaluators() => _evaluators.Value.ToList();
 486    internal static List<IValidator> GetValidators() => _validators.Value.ToList();
 87
 88    internal static List<TType> GetInstancesOf<TType, TAttribute>()
 89        where TType : class
 90        where TAttribute : DiscoveryAttribute
 691        => GetInstancesOf<TType, TAttribute>(_loadedAssemblies.Value);
 92
 93    internal static List<TType> GetInstancesOf<TType, TAttribute>(IEnumerable<Assembly> assemblies)
 94        where TType : class
 95        where TAttribute : DiscoveryAttribute
 96    {
 97        try
 98        {
 1499            var baseType = typeof(TType);
 14100            var typeInstances = new List<(TType Instance, int Order, string TypeName)>();
 101
 14102            var types = assemblies
 14103                .SelectMany(a =>
 14104                {
 83105                    try { return a.GetTypes(); } catch { return Array.Empty<Type>(); }
 83106                })
 29068107                .Where(t => t.IsClass && !t.IsAbstract && !t.ContainsGenericParameters && baseType.IsAssignableFrom(t))
 14108                .Distinct();
 109
 222110            foreach (var type in types)
 111            {
 97112                var discoveryAttr = type.GetCustomAttribute<TAttribute>();
 97113                if (discoveryAttr is not null && !discoveryAttr.Enable)
 114                    continue;
 115
 89116                TType? instance = null;
 117
 89118                if (type.GetConstructor(Type.EmptyTypes) is not null)
 119                {
 41120                    instance = (TType?)Activator.CreateInstance(type);
 121                }
 48122                else if (type.GetFields(BindingFlags.Public | BindingFlags.Static)
 32123                    .Where(f => type.IsAssignableFrom(f.FieldType))
 48124                    .FirstOrDefault() is FieldInfo instanceField)
 125                {
 32126                    instance = (TType?)instanceField.GetValue(null);
 127                }
 16128                else if (type.GetProperties(BindingFlags.Public | BindingFlags.Static)
 8129                    .Where(f => type.IsAssignableFrom(f.PropertyType))
 16130                    .FirstOrDefault() is PropertyInfo instanceProp)
 131                {
 8132                    instance = (TType?)instanceProp.GetValue(null);
 133                }
 134
 89135                if (instance is null) continue;
 136
 81137                int order = discoveryAttr?.Order ?? int.MaxValue;
 81138                typeInstances.Add((instance, order, type.Name));
 139            }
 140
 14141            return typeInstances
 81142                .OrderBy(e => e.Order)
 81143                .ThenBy(e => e.TypeName)
 81144                .Select(e => e.Instance)
 14145                .ToList();
 146        }
 0147        catch (Exception ex)
 148        {
 0149            if (_isDebugBuild.Value)
 150            {
 0151                throw new SpecAutoDiscoveryException(ex);
 152            }
 0153            return [];
 154        }
 14155    }
 156}