Skip to content

Instantly share code, notes, and snippets.

@otac0n
Created April 1, 2025 02:07
Show Gist options
  • Save otac0n/a1fe334b1eec8c5618833d728a237a15 to your computer and use it in GitHub Desktop.
Save otac0n/a1fe334b1eec8c5618833d728a237a15 to your computer and use it in GitHub Desktop.

Revisions

  1. otac0n created this gist Apr 1, 2025.
    90 changes: 90 additions & 0 deletions ToCSharpString.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,90 @@
    // usage:
    // typeof(System.Collections.Generic.List<System.Double>).ToFullyQualifiedName()
    // output:
    // System.Collections.Generic.List<System.Double>
    //
    // usage:
    // typeof(System.Collections.Generic.List<System.Double>).ToCSharpString(
    // symbolDisplayFormat: new SymbolDisplayFormat(
    // typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameOnly,
    // genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
    // miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes))
    // output:
    // List<double>

    public static string ToCSharpString(this Type type, string[] usingNamespaces = null, Assembly[] usingAssemblies = null, SymbolDisplayFormat symbolDisplayFormat = null)
    {
    var compilationUnit = SyntaxFactory.CompilationUnit();
    if (usingNamespaces != null)
    {
    compilationUnit = compilationUnit.AddUsings(
    Array.ConvertAll(usingNamespaces, n => SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(n))));
    }
    else
    {
    compilationUnit = compilationUnit.AddUsings(
    SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName("System")));
    }

    MetadataReference[] metadataReferences;
    if (usingAssemblies != null)
    {
    metadataReferences = Array.ConvertAll(usingAssemblies, u => MetadataReference.CreateFromFile(u.Location));
    }
    else
    {
    metadataReferences = new[]
    {
    MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
    MetadataReference.CreateFromFile(type.Assembly.Location)
    };
    }

    var typeName = SyntaxFactory.ParseTypeName(type.ToFullyQualifiedName());

    var field = SyntaxFactory.FieldDeclaration(
    SyntaxFactory.VariableDeclaration(typeName).WithVariables(
    SyntaxFactory.SingletonSeparatedList<VariableDeclaratorSyntax>(
    SyntaxFactory.VariableDeclarator(
    SyntaxFactory.Identifier("field")))));
    compilationUnit = compilationUnit.AddMembers(
    SyntaxFactory.ClassDeclaration("MyClass").AddMembers(
    field))
    .NormalizeWhitespace();

    var tree = compilationUnit.SyntaxTree;
    var compilation = CSharpCompilation.Create("MyAssembly", new[] { tree }, metadataReferences);
    var semanticModel = compilation.GetSemanticModel(tree);
    var root = tree.GetRoot();

    var typeSymbol = semanticModel.GetTypeInfo(compilationUnit
    .DescendantNodes().OfType<ClassDeclarationSyntax>().Single()
    .Members.OfType<FieldDeclarationSyntax>().Single()
    .Declaration.Type);

    return typeSymbol.Type.ToDisplayString(symbolDisplayFormat ?? new SymbolDisplayFormat(
    typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes,
    genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
    miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes));
    }

    public static string ToFullyQualifiedName(this Type type)
    {
    switch (type)
    {
    case { IsGenericParameter: true }: return type.Name;
    case { IsArray: true }: return type.GetElementType().ToFullyQualifiedName() + "[]";
    case { IsPointer: true }: return type.GetElementType().ToFullyQualifiedName() + "*";
    case { IsByRef: true }: return type.GetElementType().ToFullyQualifiedName() + "&";
    case { IsGenericType: false }: return string.IsNullOrEmpty(type.FullName) ? type.Name : type.FullName.Replace('+', '.');
    default:
    var fullName = type.GetGenericTypeDefinition().FullName;
    var backTickIndex = fullName.IndexOf('`');
    if (backTickIndex > 0)
    {
    fullName = fullName.Substring(0, backTickIndex);
    }

    return fullName.Replace('+', '.') + "<" + string.Join(", ", type.GetGenericArguments().Select(ToFullyQualifiedName)) + ">";
    };
    }