< Summary

Information
Class: Ice.Internal.AssemblySliceLoaderFactory
Assembly: Ice
File(s): /home/runner/work/ice/ice/csharp/src/Ice/Internal/AssemblySliceLoader.cs
Tag: 71_18251537082
Line coverage
100%
Covered lines: 34
Uncovered lines: 0
Coverable lines: 34
Total lines: 120
Line coverage: 100%
Branch coverage
100%
Covered branches: 12
Total branches: 12
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_Instance()100%11100%
.cctor()100%11100%
.ctor()100%11100%
Get(...)100%44100%

File(s)

/home/runner/work/ice/ice/csharp/src/Ice/Internal/AssemblySliceLoader.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3#nullable enable
 4
 5using System.Collections.Concurrent;
 6using System.Collections.Immutable;
 7using System.Globalization;
 8using System.Reflection;
 9
 10namespace Ice.Internal;
 11
 12/// <summary>Implements <see cref="SliceLoader" /> by searching for generated classes in the specified assemblies and
 13/// their referenced assemblies.</summary>
 14internal sealed class AssemblySliceLoader : SliceLoader
 15{
 16    internal static AssemblySliceLoader Empty { get; } =
 17        new AssemblySliceLoader(ImmutableDictionary<string, Type>.Empty);
 18
 19    private readonly IReadOnlyDictionary<string, Type> _dict;
 20
 21    /// <inheritdoc />
 22    public object? newInstance(string typeId)
 23    {
 24        if (_dict.TryGetValue(typeId, out Type? type))
 25        {
 26            try
 27            {
 28                return Activator.CreateInstance(type);
 29            }
 30            catch (System.Exception exception)
 31            {
 32                throw new MarshalException(
 33                    $"Failed to create an instance of class '{type.FullName}' for type ID '{typeId}'.", exception);
 34            }
 35        }
 36        else
 37        {
 38            return null;
 39        }
 40    }
 41
 42    /// <summary>Merge loaders into a single loader; duplicate entries are ignored.</summary>
 43    internal static AssemblySliceLoader Merge(IEnumerable<AssemblySliceLoader> loaders)
 44    {
 45        if (loaders.Count() == 1)
 46        {
 47            return loaders.First();
 48        }
 49        else
 50        {
 51            var dict = new Dictionary<string, Type>();
 52
 53            foreach (AssemblySliceLoader loader in loaders)
 54            {
 55                foreach ((string typeId, Type factory) in loader._dict)
 56                {
 57                    dict[typeId] = factory;
 58                }
 59            }
 60            return dict.Count == 0 ? Empty : new AssemblySliceLoader(dict);
 61        }
 62    }
 63
 64    internal AssemblySliceLoader(IReadOnlyDictionary<string, Type> dict) => _dict = dict;
 65}
 66
 67/// <summary>Creates Slice loaders from assemblies by mapping types in these assemblies.</summary>
 68internal sealed class AssemblySliceLoaderFactory
 69{
 170    internal static AssemblySliceLoaderFactory Instance { get; } = new AssemblySliceLoaderFactory();
 71
 172    private readonly ConcurrentDictionary<Assembly, AssemblySliceLoader> _cache = new();
 73
 74    internal AssemblySliceLoader Get(Assembly assembly)
 75    {
 176        if (_cache.TryGetValue(assembly, out AssemblySliceLoader? loader))
 77        {
 178            return loader;
 79        }
 180        else if (assembly.GetCustomAttributes<SliceAttribute>().Any())
 81        {
 182            return _cache.GetOrAdd(
 183                assembly,
 184                assembly =>
 185                {
 186                    var dict = new Dictionary<string, Type>();
 187
 188                    foreach (Type type in assembly.GetTypes())
 189                    {
 190                        // We're only interested in generated Slice classes and exceptions.
 191                        if (type.IsClass && type.GetSliceTypeId() is string typeId)
 192                        {
 193                            dict.Add(typeId, type);
 194
 195                            if (type.GetCompactSliceTypeId() is int compactTypeId)
 196                            {
 197                                dict.Add(compactTypeId.ToString(CultureInfo.InvariantCulture), type);
 198                            }
 199                        }
 1100                    }
 1101
 1102                    // Merge with the loaders of the referenced assemblies (recursive call).
 1103                    return AssemblySliceLoader.Merge(
 1104                        assembly.GetReferencedAssemblies().Select(
 1105                            assemblyName => Get(AppDomain.CurrentDomain.Load(assemblyName))).Append(
 1106                                new AssemblySliceLoader(dict)));
 1107                });
 108        }
 109        else
 110        {
 111            // We don't cache an assembly with no Slice attribute, and don't load/process its referenced assemblies.
 1112            return AssemblySliceLoader.Empty;
 113        }
 114    }
 115
 1116    private AssemblySliceLoaderFactory()
 117    {
 118        // ensures it's a singleton.
 1119    }
 120}