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;
}