/// <summary> /// Gets a readability-optimized string representation of the specified type. /// </summary> /// <remarks> /// Adapted from: <a href="https://stackoverflow.com/a/6402967/356790" />. /// Adapted from: <a href="https://stackoverflow.com/questions/1362884/is-there-a-way-to-get-a-types-alias-through-reflection" />. /// Helpful breakdown of generics: <a href="https://docs.microsoft.com/en-us/dotnet/api/system.type.isgenerictype" />. /// </remarks> /// <param name="type">The type.</param> /// <param name="options">The options to use when generating the string representation.</param> /// <returns> /// A readability-optimized string representation of the specified type. /// </returns> /// <exception cref="ArgumentNullException"><paramref name="type"/> is null.</exception> public static string ToStringReadable( this Type type, ToStringReadableOptions options = ToStringReadableOptions.None) { if (type == null) { throw new ArgumentNullException(nameof(type)); } var assemblyDetailsTypes = new List <Type>(); var result = type.ToStringReadableInternal(options, assemblyDetailsTypes); var includeAssemblyDetails = options.HasFlag(ToStringReadableOptions.IncludeAssemblyDetails); if (includeAssemblyDetails && assemblyDetailsTypes.Any()) { result = result + " || " + string.Join(" | ", assemblyDetailsTypes.Select(_ => _.ToAssemblyDetails()).ToArray()); } return(result); }
private static string ToStringReadableInternal( this Type type, ToStringReadableOptions options, IList <Type> assemblyDetailsTypes = null) { string result; if (type.IsGenericParameter) { result = type.Name; } else if (ValueTypeToAliasMap.ContainsKey(type)) { assemblyDetailsTypes?.Add(type); result = ValueTypeToAliasMap[type]; } else if (type.IsClosedNullableType()) { result = Nullable.GetUnderlyingType(type).ToStringReadableInternal(options, assemblyDetailsTypes) + "?"; } else if (type.IsArray) { result = type.GetElementType().ToStringReadableInternal(options, assemblyDetailsTypes) + "[]"; } else { assemblyDetailsTypes?.Add(type); result = CodeDomProvider.GetTypeOutput(new CodeTypeReference(type.FullName?.Replace(type.Namespace + ".", string.Empty) ?? type.Name)); var includeNamespace = options.HasFlag(ToStringReadableOptions.IncludeNamespace); if (includeNamespace && (type.Namespace != null)) { result = type.Namespace + "." + result; } if (type.IsGenericType) { var isAnonymousType = type.IsAnonymousType(); if (isAnonymousType) { result = result.Replace("<>f__", string.Empty); } string[] genericParameters; if (isAnonymousType && type.ContainsGenericParameters) { genericParameters = type.GetGenericArguments().Select((_, i) => "T" + (i + 1).ToString(CultureInfo.InvariantCulture)).ToArray(); } else { genericParameters = type.GetGenericArguments().Select(_ => _.ToStringReadableInternal(options, assemblyDetailsTypes)).ToArray(); } result = GenericBracketsRegex.Replace(result, "<" + string.Join(", ", genericParameters) + ">"); } } return(result); }