< Summary

Information
Class: Elsa.Api.Client.Extensions.TypeExtensions
Assembly: Elsa.Api.Client
File(s): /home/runner/work/elsa-core/elsa-core/src/clients/Elsa.Api.Client/Extensions/TypeExtensions.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 36
Coverable lines: 36
Total lines: 98
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 34
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%210%
GetSimpleAssemblyQualifiedName(...)0%620%
GetDefaultValue(...)0%620%
GetEnumerableElementType(...)0%2040%
FindIEnumerable(...)0%600240%
BuildSimplifiedName(...)0%620%

File(s)

/home/runner/work/elsa-core/elsa-core/src/clients/Elsa.Api.Client/Extensions/TypeExtensions.cs

#LineLine coverage
 1using System.Collections.Concurrent;
 2
 3namespace Elsa.Api.Client.Extensions;
 4
 5/// <summary>
 6/// Adds extension methods to <see cref="Type"/>.
 7/// </summary>
 8public static class TypeExtensions
 9{
 010    private static readonly ConcurrentDictionary<Type, string> SimpleAssemblyQualifiedTypeNameCache = new();
 11
 12    /// <summary>
 13    /// Gets the assembly-qualified name of the type, without any version info etc.
 14    /// E.g. "System.String, System.Private.CoreLib"
 15    /// </summary>
 16    public static string GetSimpleAssemblyQualifiedName(this Type type)
 17    {
 018        if (type is null) throw new ArgumentNullException(nameof(type));
 019        return SimpleAssemblyQualifiedTypeNameCache.GetOrAdd(type, BuildSimplifiedName);
 20    }
 21
 22    /// <summary>
 23    /// Returns the default value for the specified type.
 24    /// </summary>
 025    public static object? GetDefaultValue(this Type type) => type.IsClass ? null : Activator.CreateInstance(type);
 26
 27    /// <summary>
 28    /// Returns the element type of the specified type representing an array or generic enumerable.
 29    /// </summary>
 30    public static Type GetEnumerableElementType(this Type type)
 31    {
 032        if (type.IsArray)
 033            return type.GetElementType()!;
 34
 035        var elementType = FindIEnumerable(type);
 036        return elementType == null ? type : elementType.GetGenericArguments()[0];
 37    }
 38
 39    /// <summary>
 40    /// Searches for the first implemented IEnumerable interface in the given type hierarchy, and returns the generic ty
 41    /// </summary>
 42    /// <param name="sequenceType">The type to search for the IEnumerable interface.</param>
 43    /// <returns>The generic type argument of the first implemented IEnumerable interface found in the type hierarchy, o
 44    private static Type? FindIEnumerable(Type? sequenceType)
 45    {
 046        if (sequenceType == null || sequenceType == typeof(string))
 047            return null;
 48
 049        if (sequenceType.IsArray)
 050            return typeof(IEnumerable<>).MakeGenericType(sequenceType.GetElementType()!);
 51
 052        if (sequenceType.IsGenericType)
 53        {
 054            foreach (var arg in sequenceType.GetGenericArguments())
 55            {
 056                var enumerable = typeof(IEnumerable<>).MakeGenericType(arg);
 057                if (enumerable.IsAssignableFrom(sequenceType))
 058                    return enumerable;
 59            }
 60        }
 61
 062        var interfaces = sequenceType.GetInterfaces();
 63
 064        if (interfaces is { Length: > 0 })
 65        {
 066            foreach (var interfaceType in interfaces)
 67            {
 068                var enumerable = FindIEnumerable(interfaceType);
 069                if (enumerable != null) return enumerable;
 70            }
 71        }
 072        if (sequenceType.BaseType != null && sequenceType.BaseType != typeof(object))
 073            return FindIEnumerable(sequenceType.BaseType);
 74
 075        return null;
 76    }
 77
 78    private static string BuildSimplifiedName(Type type)
 79    {
 080        var assemblyName = type.Assembly.GetName().Name;
 81
 082        if (type.IsGenericType)
 83        {
 084            var genericTypeName = type.GetGenericTypeDefinition().FullName!;
 085            var backtickIndex = genericTypeName.IndexOf('`');
 086            var typeNameWithoutArity = genericTypeName[..backtickIndex];
 087            var arity = genericTypeName[backtickIndex..];
 88
 089            var genericArguments = type.GetGenericArguments();
 090            var simplifiedGenericArguments = genericArguments.Select(BuildSimplifiedName);
 91
 092            return $"{typeNameWithoutArity}{arity}[[{string.Join("],[", simplifiedGenericArguments)}]], {assemblyName}";
 93        }
 94
 095        var typeName = type.FullName;
 096        return $"{typeName}, {assemblyName}";
 97    }
 98}