Exemple #1
0
        /// <summary>
        ///   Gets a string representation of this instance.
        /// </summary>
        /// <param name="type">The <see cref="Type"/> of which a string representation is requested.</param>
        /// <param name="options">Any combination of formatting options that should be applied. (Optional.)</param>
        /// <returns>A string representation of this instance.</returns>
        public static string GetFormattedName(this Type type, TypeNameFormatOptions options = TypeNameFormatOptions.Default)
        {
            var stringBuilder = new StringBuilder();

            stringBuilder.AppendFormattedName(type, options);
            return(stringBuilder.ToString());
        }
Exemple #2
0
        private static void AppendFormattedName(this StringBuilder stringBuilder, Type type, TypeNameFormatOptions options, Type typeWithGenericTypeArgs)
        {
            // PHASE 1: Rule out several special cases. (These are mostly "composite" types requiring some recursion.)

            // Types for which there is a keyword:
            if (IsSet(TypeNameFormatOptions.NoKeywords, options) == false && typeKeywords.TryGetValue(type, out string typeKeyword))
            {
                stringBuilder.Append(typeKeyword);
                return;
            }

            // Arrays, by-ref, and pointer types:
            if (type.HasElementType)
            {
                var elementType = type.GetElementType();

                if (type.IsArray)
                {
                    var ranks = new Queue <int>();
                    ranks.Enqueue(type.GetArrayRank());
                    HandleArrayElementType(elementType, ranks);

                    void HandleArrayElementType(Type et, Queue <int> r)
                    {
                        if (et.IsArray)
                        {
                            r.Enqueue(et.GetArrayRank());
                            HandleArrayElementType(et.GetElementType(), r);
                        }
                        else
                        {
                            stringBuilder.AppendFormattedName(et, options);
                            while (r.Count > 0)
                            {
                                stringBuilder.Append('[');
                                stringBuilder.Append(',', r.Dequeue() - 1);
                                stringBuilder.Append(']');
                            }
                        }
                    }
                }
                else if (type.IsByRef)
                {
                    stringBuilder.Append("ref ");
                    stringBuilder.AppendFormattedName(elementType, options);
                }
                else
                {
                    Debug.Assert(type.IsPointer, "Only array, by-ref, and pointer types have an element type.");

                    stringBuilder.AppendFormattedName(elementType, options);
                    stringBuilder.Append('*');
                }

                return;
            }

            var isConstructedGenericType = IsConstructedGenericType(typeWithGenericTypeArgs);

            if (isConstructedGenericType)
            {
                // Nullable value types (excluding the open generic Nullable<T> itself):
                if (IsSet(TypeNameFormatOptions.NoNullableQuestionMark, options) == false)
                {
                    var nullableArg = Nullable.GetUnderlyingType(type);
                    if (nullableArg != null)
                    {
                        stringBuilder.AppendFormattedName(nullableArg, options);
                        stringBuilder.Append('?');
                        return;
                    }
                }

                // Value tuple types (any type called System.ValueTuple`n):
                if (IsSet(TypeNameFormatOptions.NoTuple, options) == false && type.Name.StartsWith("ValueTuple`", StringComparison.Ordinal) && type.Namespace == "System")
                {
                    var genericTypeArgs = GetGenericTypeArguments(typeWithGenericTypeArgs);

                    stringBuilder.Append('(');
                    for (int i = 0, n = genericTypeArgs.Length; i < n; ++i)
                    {
                        if (i > 0)
                        {
                            stringBuilder.Append(", ");
                        }

                        stringBuilder.AppendFormattedName(genericTypeArgs[i], options);
                    }

                    stringBuilder.Append(')');
                    return;
                }
            }

            var name = type.Name;

            if (IsSet(TypeNameFormatOptions.NoAnonymousTypes, options) == false && name.StartsWith("<>f", StringComparison.Ordinal))
            {
                stringBuilder.Append('{');

                int i = 0;
                foreach (var property in GetDeclaredProperties(type))
                {
                    if (i > 0)
                    {
                        stringBuilder.Append(", ");
                    }

                    stringBuilder.AppendFormattedName(property.PropertyType, options)
                    .Append(' ')
                    .Append(property.Name);

                    ++i;
                }

                stringBuilder.Append('}');
                return;
            }

            // PHASE 2: Format a (non-"composite") type's name.

            // Possible prefix (namespace or name of enclosing type):
            if (!type.IsGenericParameter)
            {
                if (type.IsNested)
                {
                    stringBuilder.AppendFormattedName(type.DeclaringType, options, typeWithGenericTypeArgs);
                    stringBuilder.Append('.');
                }
                else if (IsSet(TypeNameFormatOptions.Namespaces, options))
                {
                    string @namespace = type.Namespace;
                    if (string.IsNullOrEmpty(@namespace) == false)
                    {
                        stringBuilder.Append(type.Namespace);
                        stringBuilder.Append('.');
                    }
                }
            }

            // Actual type name, optionally followed by a generic parameter/argument list:
            if (isConstructedGenericType || IsGenericType(type))
            {
                var backtickIndex = name.LastIndexOf('`');
                if (backtickIndex >= 0)
                {
                    stringBuilder.Append(name, 0, backtickIndex);
                }
                else
                {
                    stringBuilder.Append(name);
                }

                var ownGenericTypeParamCount = GetGenericTypeArguments(type).Length;

                int ownGenericTypeArgStartIndex = 0;
                if (type.IsNested)
                {
                    var outerTypeGenericTypeParamCount = GetGenericTypeArguments(type.DeclaringType).Length;
                    if (ownGenericTypeParamCount >= outerTypeGenericTypeParamCount)
                    {
                        ownGenericTypeArgStartIndex = outerTypeGenericTypeParamCount;
                    }
                }

                if (ownGenericTypeArgStartIndex < ownGenericTypeParamCount)
                {
                    stringBuilder.Append('<');

                    if (isConstructedGenericType || IsSet(TypeNameFormatOptions.NoGenericParameterNames, options) == false)
                    {
                        var genericTypeArgs = GetGenericTypeArguments(typeWithGenericTypeArgs);

                        for (int i = ownGenericTypeArgStartIndex, n = ownGenericTypeParamCount; i < n; ++i)
                        {
                            if (i > ownGenericTypeArgStartIndex)
                            {
                                stringBuilder.Append(", ");
                            }

                            stringBuilder.AppendFormattedName(genericTypeArgs[i], options);
                        }
                    }
                    else
                    {
                        stringBuilder.Append(',', ownGenericTypeParamCount - ownGenericTypeArgStartIndex - 1);
                    }

                    stringBuilder.Append('>');
                }
            }
            else
            {
                stringBuilder.Append(name);
            }
        }
Exemple #3
0
 /// <summary>
 ///   Appends a string representation of the specified type to this instance.
 /// </summary>
 /// <param name="stringBuilder">The <see cref="StringBuilder"/> instance to which to append.</param>
 /// <param name="type">The <see cref="Type"/> of which a string representation should be appended.</param>
 /// <param name="options">Any combination of formatting options that should be applied. (Optional.)</param>
 /// <returns>A reference to this instance after the append operation has completed.</returns>
 public static StringBuilder AppendFormattedName(this StringBuilder stringBuilder, Type type, TypeNameFormatOptions options = TypeNameFormatOptions.Default)
 {
     stringBuilder.AppendFormattedName(type, options, type);
     return(stringBuilder);
 }
Exemple #4
0
        private static void WriteNamePart(TypeInfo type, StringBuilder builder, ArraySegment <TypeInfo> genericArguments, TypeNameFormatOptions options)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }

            builder.Append(type.Name);

            if (genericArguments.Count > 0)
            {
                builder.Append("<");
                for (var i = genericArguments.Offset; i < genericArguments.Offset + genericArguments.Count; i++)
                {
                    // ReSharper disable once PossibleNullReferenceException
                    if (genericArguments.Array[i].IsGenericParameter == false)
                    {
                        WriteName(genericArguments.Array[i], builder, options);
                    }
                    builder.Append(',');
                }
                builder.Length--;
                builder.Append(">");
            }
        }
Exemple #5
0
 /// <remarks>
 ///   Replacement for <see cref="M:System.Enum.HasFlag(System.Enum)"/>
 ///   which may be slow or even unavailable on earlier target frameworks.
 /// </remarks>
 private static bool IsSet(TypeNameFormatOptions option, TypeNameFormatOptions options)
 {
     return((options & option) == option);
 }
Exemple #6
0
        public static StringBuilder GetCSharpFullName(this Type type, StringBuilder builder = null, TypeNameFormatOptions options = TypeNameFormatOptions.IncludeGenericSuffix)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            return(GetCSharpFullName(type.GetTypeInfo(), builder, options));
        }
Exemple #7
0
        private static void WriteName(TypeInfo typeInfo, StringBuilder builder, TypeNameFormatOptions options)
        {
            if (typeInfo == null)
            {
                throw new ArgumentNullException("typeInfo");
            }
            if (builder == null)
            {
                throw new ArgumentNullException("builder");
            }

            var alias = default(string);

            if ((options & TypeNameFormatOptions.UseAliases) == TypeNameFormatOptions.UseAliases &&
                CSharpTypeNameAlias.TryGetAlias(typeInfo, out alias))
            {
                builder.Append(alias);
                return;
            }

            var arrayDepth = 0;

            while (typeInfo.IsArray)
            {
                typeInfo = typeInfo.GetElementType().GetTypeInfo();
                arrayDepth++;
            }

            var writeGenericArguments = (options & TypeNameFormatOptions.IncludeGenericArguments) == TypeNameFormatOptions.IncludeGenericArguments;
            var namespaceWritten      = (options & TypeNameFormatOptions.IncludeNamespace) != TypeNameFormatOptions.IncludeNamespace;
            var writeDeclaringType    = (options & TypeNameFormatOptions.IncludeDeclaringType) == TypeNameFormatOptions.IncludeDeclaringType;

            var genericArguments      = (typeInfo.IsGenericType && writeGenericArguments ? typeInfo.GetGenericArguments() : Type.EmptyTypes).ConvertAll(t => t.GetTypeInfo());
            var genericArgumentOffset = 0;

            foreach (var declaringTypeInfo in new TypeNestingEnumerator(typeInfo))
            {
                if (!namespaceWritten)
                {
                    var typeNamespace = declaringTypeInfo.Namespace;
                    builder.Append(typeNamespace);
                    if (!string.IsNullOrEmpty(typeNamespace))
                    {
                        builder.Append('.');
                    }
                    namespaceWritten = true;
                }

                var genericArgumentsCount = (declaringTypeInfo.IsGenericType && writeGenericArguments ? declaringTypeInfo.GetGenericArguments().Length : 0) - genericArgumentOffset;
                var partialGenerics       = new ArraySegment <TypeInfo>(genericArguments, genericArgumentOffset, genericArgumentsCount);

                if (writeDeclaringType || declaringTypeInfo.Equals(typeInfo))
                {
                    WriteNamePart(declaringTypeInfo, builder, partialGenerics, options);

                    if (declaringTypeInfo.Equals(typeInfo) == false)
                    {
                        builder.Append('.');
                    }
                }

                genericArgumentOffset += genericArgumentsCount;
            }

            for (var d = 0; d < arrayDepth; d++)
            {
                builder.Append("[]");
            }
        }
Exemple #8
0
        public static StringBuilder GetCSharpNameOnly(this TypeInfo typeInfo, StringBuilder builder = null, TypeNameFormatOptions options = TypeNameFormatOptions.IncludeGenericSuffix)
        {
            if (typeInfo == null)
            {
                throw new ArgumentNullException("typeInfo");
            }

            if (builder == null)
            {
                builder = new StringBuilder();
            }

            var nameStartIndex = builder.Length;

            WriteName(typeInfo, builder, options & ~TypeNameFormatOptions.IncludeNamespace);

            if ((options & TypeNameFormatOptions.IncludeGenericSuffix) == 0)
            {
                RemoveGenericSuffix(builder, nameStartIndex, builder.Length - nameStartIndex);
            }

            return(builder);
        }
Exemple #9
0
 public void Anonymous_type(string expectedFormattedName, object anonymouslyTypedObj, TypeNameFormatOptions options)
 {
     Assert.Equal(expectedFormattedName, anonymouslyTypedObj.GetType().GetFormattedName(options));
 }
Exemple #10
0
 public void Generic_type_parameter_acting_as_argument_in_constructed_type(string expectedFormattedName, Type type, TypeNameFormatOptions options)
 {
     Assert.Equal(expectedFormattedName, type.GetFormattedName(options));
 }
Exemple #11
0
 public void Value_tuple(string expectedFormattedName, Type type, TypeNameFormatOptions options)
 {
     Assert.Equal(expectedFormattedName, type.GetFormattedName(options));
 }
Exemple #12
0
 public void Nested_generic_type_instantiation(string expectedFormattedName, Type type, TypeNameFormatOptions options)
 {
     Assert.Equal(expectedFormattedName, type.GetFormattedName(options));
 }