< Summary

Information
Class: ZeroC.Slice.Internal.Activator
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: 18
Uncovered lines: 0
Coverable lines: 18
Total lines: 98
Line coverage: 100%
Branch coverage
100%
Covered branches: 10
Total branches: 10
Branch coverage: 100%
Method coverage
100%
Covered methods: 4
Total methods: 4
Method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Empty()100%11100%
CreateInstance(...)100%22100%
Merge(...)87.5%88100%
.ctor(...)100%11100%

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{
 26413    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) =>
 24618        _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)
 1622    {
 1623        if (activators.Count() == 1)
 224        {
 225            return activators.First();
 26        }
 27        else
 1428        {
 1429            var dict = new Dictionary<string, Type>();
 30
 33631            foreach (Activator activator in activators)
 14732            {
 85933                foreach ((string typeId, Type factory) in activator._dict)
 20934                {
 20935                    dict[typeId] = factory;
 20936                }
 14737            }
 1438            return dict.Count == 0 ? Empty : new Activator(dict);
 39        }
 1640    }
 41
 6042    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{
 48    internal static ActivatorFactory Instance { get; } = new ActivatorFactory();
 49
 50    private readonly ConcurrentDictionary<Assembly, Activator> _cache = new();
 51
 52    internal Activator Get(Assembly assembly)
 53    {
 54        if (_cache.TryGetValue(assembly, out Activator? activator))
 55        {
 56            return activator;
 57        }
 58        else if (assembly.GetCustomAttributes<SliceAttribute>().Any())
 59        {
 60            return _cache.GetOrAdd(
 61                assembly,
 62                assembly =>
 63                {
 64                    var dict = new Dictionary<string, Type>();
 65
 66                    foreach (Type type in assembly.GetTypes())
 67                    {
 68                        // We're only interested in generated Slice classes and exceptions.
 69                        if (type.IsClass && type.GetSliceTypeId() is string typeId)
 70                        {
 71                            dict.Add(typeId, type);
 72
 73                            if (type.GetCompactSliceTypeId() is int compactTypeId)
 74                            {
 75                                dict.Add(compactTypeId.ToString(CultureInfo.InvariantCulture), type);
 76                            }
 77                        }
 78                    }
 79
 80                    // Merge with the activators of the referenced assemblies (recursive call)
 81                    return Activator.Merge(
 82                        assembly.GetReferencedAssemblies().Select(
 83                            assemblyName => Get(AppDomain.CurrentDomain.Load(assemblyName))).Append(
 84                                new Activator(dict)));
 85                });
 86        }
 87        else
 88        {
 89            // We don't cache an assembly with no Slice attribute, and don't load/process its referenced assemblies.
 90            return Activator.Empty;
 91        }
 92    }
 93
 94    private ActivatorFactory()
 95    {
 96        // ensures it's a singleton.
 97    }
 98}