I am writing a function that takes any concrete or constructed Type, say for example typeof(ValueTuple<Nullable<System.Int32>, double, List<string>>) and returns a string that is the reduced C# syntax representation of that type (i.e. (int?, double, List<string>) in this example).
Here's what I have so far:
public static string ToCSharpString(this Type type, string[] usingNamespaces = null, Assembly[] usingAssemblies = 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)
};
}
TypeSyntax typeName;
using (var provider = new CSharpCodeProvider())
{
typeName = SyntaxFactory.ParseTypeName(provider.GetTypeOutput(new CodeTypeReference(type)));
}
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.GetDeclaredSymbol(compilationUnit
.DescendantNodes().OfType<ClassDeclarationSyntax>().Single()
.Members.OfType<FieldDeclarationSyntax>().Single()
.Declaration.Type);
return typeSymbol.ToDisplayString(new SymbolDisplayFormat(
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameOnly,
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes));
}
I'm attempting to string together a couple of known methods for converting types.
- Type -> Fully Qualified Name
- via CodeDOM's CSharpCodeProvider.GetTypeOutput
- Fully Qualified Name -> TypeSyntax
- via Rosly's SyntaxFactory.ParseTypeName
Now I would like to use .ToDisplayString() with a few different options, but I can't find a type node for my type that doesn't return null from the semantic model.
How can I format a TypeSyntax using a SymbolDisplayFormat?
In addition, I expect that this will change System.Int32 -> int, however, it won't automatically fix instances of Nullable<T> or ValueTuple<T1...>
How can I execute the appropriate code analysis rules to replace these type names?