public override string ToString()

in Agents/Xamarin.Interactive/Representations/Reflection/TypeSpec.cs [319:418]


        public override string ToString ()
            => ToString (false);

        public string ToString (bool withAssemblyQualifiedName)
            => AppendFullTypeSpec (
                new StringBuilder (),
                withAssemblyQualifiedName && !string.IsNullOrEmpty (AssemblyName),
                depth: 0).ToString ();

        #endregion

        #region Parsing

        // FIXME: Type.IsVariableBoundArray/Type.IsSZArray is missing in .NET Standard 2.0
        static readonly PropertyInfo IsVariableBoundArray = typeof (Type)
            .GetProperty (nameof (IsVariableBoundArray));

        static readonly ConcurrentDictionary<Type, TypeSpec> typeSpecCache
            = new ConcurrentDictionary<Type, TypeSpec> ();

        public static TypeSpec Create (Type type)
        {
            if (type == null)
                throw new ArgumentNullException (nameof (type));

            var originalType = type;
            if (typeSpecCache.TryGetValue (originalType, out var typeSpec))
                return typeSpec;

            TypeName outerTypeName = default;
            List<TypeName> nestedNames = null;
            List<Modifier> modifiers = null;
            List<TypeSpec> typeArgumentList = null;

            // desugar the type to separate the unmodified type from its modifiers
            // (e.g. 'System.Int32**[,,]&' -> 'System.Int32' + '**[,,]&' )
            while (type.HasElementType) {
                if (modifiers == null)
                    modifiers = new List<Modifier> ();

                if (type.IsByRef)
                    modifiers.Insert (0, Modifier.ByRef);
                else if (type.IsPointer)
                    modifiers.Insert (0, Modifier.Pointer);
                else if (type.IsArray) {
                    var rank = type.GetArrayRank ();
                    if (rank == 1 && (bool)IsVariableBoundArray.GetValue (type))
                        modifiers.Insert (0, Modifier.BoundArray);
                    else
                        modifiers.Insert (0, (Modifier)(byte)rank);
                }

                type = type.GetElementType ();
            }

            // handle generic type arguments for open (e.g <,>) and closed (e.g. <int, string>) types
            if (type.IsGenericType) {
                typeArgumentList = new List<TypeSpec> ();

                foreach (var typeArgument in type.GetGenericArguments ()) {
                    if (type.IsConstructedGenericType)
                        // recurse into constructed type arguments
                        typeArgumentList.Add (Create (typeArgument));
                    else
                        // open generics simply have a type name
                        typeArgumentList.Add (new TypeSpec (
                            new TypeName (null, typeArgument.Name)));
                }
            }

            // walk nested type chain
            while (type != null) {
                // only provide the namespace on the outer-most type
                var typeName = TypeName.Parse (
                    type.DeclaringType == null ? type.Namespace : null,
                    type.Name);

                if (type.DeclaringType == null) {
                    outerTypeName = typeName;
                } else {
                    if (nestedNames == null)
                        nestedNames = new List<TypeName> ();
                    nestedNames.Insert (0, typeName);
                }

                // move up the nested chain
                type = type.DeclaringType;
            }

            typeSpec = new TypeSpec (
                outerTypeName,
                originalType.Assembly.FullName,
                nestedNames,
                modifiers,
                typeArgumentList);

            typeSpecCache [originalType] = typeSpec;

            return typeSpec;
        }