mercredi 16 novembre 2022

C#, trying to create human readable type name

I am trying to generate a human readable string for e.g. ICollection<string> or any other generic ICollection<> / IList<> / IEnumerable<>

In order to do this I use amongst others the following routine:

public static string HumanReadableTypeName(this Type aType)
    {
        if (aType == null)
            throw new ArgumentNullException($"{nameof(ReflectionExtensions)}.{nameof(HumanReadableTypeName)}");
        var lBaseType = Nullable.GetUnderlyingType(aType);
        if (lBaseType != null)
            return cNullableHdr + HumanReadableTypeName(lBaseType);
        if (aType == typeof(string))
            return aType.Name;
        if (aType.IsArray)
        {
            var elementTypeName = HumanReadableTypeName(aType.GetElementType());
            var lBuilder = new StringBuilder(elementTypeName);
            for (var i = 0; i < aType.GetArrayRank(); i++) // add brackets for each dimension
                lBuilder.Append("[]");
            return lBuilder.ToString();
        }
        var listtype = aType.GetInterfaces().Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IList<>)).FirstOrDefault();
        if (listtype != null)
        {
            var itemType = listtype.GetGenericArguments().Single();
            var itemTypeName = HumanReadableTypeName(itemType);
            return $"IList<{itemTypeName}>";

        }
        var collectiontype = aType.GetInterfaces().Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>)).FirstOrDefault();
        if (collectiontype != null)
        {
            var itemType = collectiontype.GetGenericArguments().Single();
            var itemTypeName = HumanReadableTypeName(itemType);
            return $"ICollection<{itemTypeName}>";

        }
        var enumerabletype = aType.GetInterfaces().Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>)).FirstOrDefault();
        if (enumerabletype != null)
        {
            var itemType = enumerabletype.GetGenericArguments().Single();
            var itemTypeName = HumanReadableTypeName(itemType);
            return $"IEnumerable<{itemTypeName}>";
        }
        return aType.Name;
    }

Trouble is that when I pass typeof(ICollection<string>) as an argument I get IEnumerable<string> as an answer.

In the debugger I entered:

typeof(ICollection<string>).GetInterfaces()

with as result a collection of just 2 elements:

+       [0] {Name = "IEnumerable`1" FullName = "System.Collections.Generic.IEnumerable`1[[System.String, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]"}  System.Type {System.RuntimeType}
+       [1] {Name = "IEnumerable" FullName = "System.Collections.IEnumerable"}  System.Type {System.RuntimeType}

So it seems the ICollection<> interface isn't listed!

What confuses me also is that the following statement:

typeof(ICollection<string>).Name

returns:

"ICollection`1"

So the debugger appears to be able to show it is an ICollection of some kind.

Am I overlooking something, is this featured behavior, or is it a bug in VS22 / .NET7

TIA





Aucun commentaire:

Enregistrer un commentaire