< Summary

Information
Class: ZeroC.Slice.Internal.ActivatorFactory
Assembly: ZeroC.Slice
File(s): /home/runner/work/icerpc-csharp/icerpc-csharp/src/ZeroC.Slice/Internal/Activator.cs
Tag: 275_13775359185
Line coverage
100%
Covered lines: 40
Uncovered lines: 0
Coverable lines: 40
Total lines: 98
Line coverage: 100%
Branch coverage
100%
Covered branches: 4
Total branches: 4
Branch coverage: 100%
Method coverage
100%
Covered methods: 3
Total methods: 3
Method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Instance()100%11100%
.ctor()100%11100%
Get(...)100%44100%

File(s)

/home/runner/work/icerpc-csharp/icerpc-csharp/src/ZeroC.Slice/Internal/Activator.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using System.Collections.Concurrent;
 4using System.Collections.Immutable;
 5using System.Globalization;
 6using System.Reflection;
 7
 8namespace ZeroC.Slice.Internal;
 9
 10/// <summary>The default implementation of <see cref="IActivator" />, which uses a dictionary.</summary>
 11internal class Activator : IActivator
 12{
 13    internal static Activator Empty { get; } = new Activator(ImmutableDictionary<string, Type>.Empty);
 14
 15    private readonly IReadOnlyDictionary<string, Type> _dict;
 16
 17    public object? CreateInstance(string typeId) =>
 18        _dict.TryGetValue(typeId, out Type? type) ? System.Activator.CreateInstance(type) : null;
 19
 20    /// <summary>Merge activators into a single activator; duplicate entries are ignored.</summary>
 21    internal static Activator Merge(IEnumerable<Activator> activators)
 22    {
 23        if (activators.Count() == 1)
 24        {
 25            return activators.First();
 26        }
 27        else
 28        {
 29            var dict = new Dictionary<string, Type>();
 30
 31            foreach (Activator activator in activators)
 32            {
 33                foreach ((string typeId, Type factory) in activator._dict)
 34                {
 35                    dict[typeId] = factory;
 36                }
 37            }
 38            return dict.Count == 0 ? Empty : new Activator(dict);
 39        }
 40    }
 41
 42    internal Activator(IReadOnlyDictionary<string, Type> dict) => _dict = dict;
 43}
 44
 45/// <summary>Creates activators from assemblies by processing types in those assemblies.</summary>
 46internal class ActivatorFactory
 47{
 11848    internal static ActivatorFactory Instance { get; } = new ActivatorFactory();
 49
 850    private readonly ConcurrentDictionary<Assembly, Activator> _cache = new();
 51
 52    internal Activator Get(Assembly assembly)
 38053    {
 38054        if (_cache.TryGetValue(assembly, out Activator? activator))
 11655        {
 11656            return activator;
 57        }
 26458        else if (assembly.GetCustomAttributes<SliceAttribute>().Any())
 1259        {
 1260            return _cache.GetOrAdd(
 1261                assembly,
 1262                assembly =>
 1263                {
 1264                    var dict = new Dictionary<string, Type>();
 1265
 455066                    foreach (Type type in assembly.GetTypes())
 225767                    {
 1268                        // We're only interested in generated Slice classes and exceptions.
 225769                        if (type.IsClass && type.GetSliceTypeId() is string typeId)
 6370                        {
 6371                            dict.Add(typeId, type);
 1272
 6373                            if (type.GetCompactSliceTypeId() is int compactTypeId)
 1074                            {
 1075                                dict.Add(compactTypeId.ToString(CultureInfo.InvariantCulture), type);
 1076                            }
 6377                        }
 225778                    }
 1279
 1280                    // Merge with the activators of the referenced assemblies (recursive call)
 1281                    return Activator.Merge(
 1282                        assembly.GetReferencedAssemblies().Select(
 26283                            assemblyName => Get(AppDomain.CurrentDomain.Load(assemblyName))).Append(
 1284                                new Activator(dict)));
 2485                });
 86        }
 87        else
 25288        {
 89            // We don't cache an assembly with no Slice attribute, and don't load/process its referenced assemblies.
 25290            return Activator.Empty;
 91        }
 38092    }
 93
 894    private ActivatorFactory()
 895    {
 96        // ensures it's a singleton.
 897    }
 98}