< Summary

Information
Class: Ice.Internal.AssemblySliceLoader
Assembly: Ice
File(s): /home/runner/work/ice/ice/csharp/src/Ice/Internal/AssemblySliceLoader.cs
Tag: 71_18251537082
Line coverage
76%
Covered lines: 13
Uncovered lines: 4
Coverable lines: 17
Total lines: 120
Line coverage: 76.4%
Branch coverage
80%
Covered branches: 8
Total branches: 10
Branch coverage: 80%
Method coverage
100%
Covered methods: 5
Total methods: 5
Method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_Empty()100%11100%
.cctor()100%11100%
newInstance(...)100%2.31257.14%
Merge(...)75%8.19885.71%
.ctor(...)100%11100%

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{
 116    internal static AssemblySliceLoader Empty { get; } =
 117        new AssemblySliceLoader(ImmutableDictionary<string, Type>.Empty);
 18
 19    private readonly IReadOnlyDictionary<string, Type> _dict;
 20
 21    /// <inheritdoc />
 22    public object? newInstance(string typeId)
 23    {
 124        if (_dict.TryGetValue(typeId, out Type? type))
 25        {
 26            try
 27            {
 128                return Activator.CreateInstance(type);
 29            }
 030            catch (System.Exception exception)
 31            {
 032                throw new MarshalException(
 033                    $"Failed to create an instance of class '{type.FullName}' for type ID '{typeId}'.", exception);
 34            }
 35        }
 36        else
 37        {
 138            return null;
 39        }
 140    }
 41
 42    /// <summary>Merge loaders into a single loader; duplicate entries are ignored.</summary>
 43    internal static AssemblySliceLoader Merge(IEnumerable<AssemblySliceLoader> loaders)
 44    {
 145        if (loaders.Count() == 1)
 46        {
 047            return loaders.First();
 48        }
 49        else
 50        {
 151            var dict = new Dictionary<string, Type>();
 52
 153            foreach (AssemblySliceLoader loader in loaders)
 54            {
 155                foreach ((string typeId, Type factory) in loader._dict)
 56                {
 157                    dict[typeId] = factory;
 58                }
 59            }
 160            return dict.Count == 0 ? Empty : new AssemblySliceLoader(dict);
 61        }
 62    }
 63
 164    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{
 70    internal static AssemblySliceLoaderFactory Instance { get; } = new AssemblySliceLoaderFactory();
 71
 72    private readonly ConcurrentDictionary<Assembly, AssemblySliceLoader> _cache = new();
 73
 74    internal AssemblySliceLoader Get(Assembly assembly)
 75    {
 76        if (_cache.TryGetValue(assembly, out AssemblySliceLoader? loader))
 77        {
 78            return loader;
 79        }
 80        else if (assembly.GetCustomAttributes<SliceAttribute>().Any())
 81        {
 82            return _cache.GetOrAdd(
 83                assembly,
 84                assembly =>
 85                {
 86                    var dict = new Dictionary<string, Type>();
 87
 88                    foreach (Type type in assembly.GetTypes())
 89                    {
 90                        // We're only interested in generated Slice classes and exceptions.
 91                        if (type.IsClass && type.GetSliceTypeId() is string typeId)
 92                        {
 93                            dict.Add(typeId, type);
 94
 95                            if (type.GetCompactSliceTypeId() is int compactTypeId)
 96                            {
 97                                dict.Add(compactTypeId.ToString(CultureInfo.InvariantCulture), type);
 98                            }
 99                        }
 100                    }
 101
 102                    // Merge with the loaders of the referenced assemblies (recursive call).
 103                    return AssemblySliceLoader.Merge(
 104                        assembly.GetReferencedAssemblies().Select(
 105                            assemblyName => Get(AppDomain.CurrentDomain.Load(assemblyName))).Append(
 106                                new AssemblySliceLoader(dict)));
 107                });
 108        }
 109        else
 110        {
 111            // We don't cache an assembly with no Slice attribute, and don't load/process its referenced assemblies.
 112            return AssemblySliceLoader.Empty;
 113        }
 114    }
 115
 116    private AssemblySliceLoaderFactory()
 117    {
 118        // ensures it's a singleton.
 119    }
 120}