如何使用 Roslyn 在给定的命名空间上下文中获取任意类型的最完全简化的类型名称?
How can I get the most fully reduced type name of an arbitrary type in a given namespace context using Roslyn?
我正在编写一个函数,它接受任何具体的或构造的 Type
,例如 typeof(ValueTuple<Nullable<System.Int32>, double, List<string>>)
和 returns 一个字符串,它是该类型的简化 C# 语法表示(即(int?, double, List<string>)
在这个例子中)。
这是我目前的情况:
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));
}
我正在尝试将几种已知的类型转换方法组合在一起。
- 类型 -> 完全限定名称
- 通过 CodeDOM 的 CSharpCodeProvider.GetTypeOutput
- 完全限定名称 -> TypeSyntax
- 通过 Rosly 的 SyntaxFactory.ParseTypeName
现在我想将 .ToDisplayString()
与几个不同的选项一起使用,但我无法从语义模型中为我的类型找到不为 return null 的类型节点。
如何使用 SymbolDisplayFormat 格式化 TypeSyntax?
此外,我希望这个 将 更改 System.Int32
-> int
,但是,它不会自动修复 [=17] 的实例=] 或 ValueTuple<T1...>
如何执行适当的代码分析规则来替换这些类型名称?
文档状态 GetDeclaredSymbol
仅适用于
any type derived from MemberDeclarationSyntax, TypeDeclarationSyntax, EnumDeclarationSyntax, NamespaceDeclarationSyntax, ParameterSyntax, TypeParameterSyntax, or the alias part of a UsingDirectiveSyntax
你的似乎是 QualifiedNameSyntax
这似乎与预期的输入非常一致,但显然对 Roslyn 意味着其他东西(我承认我没有费心去检查它是否真的继承自预期的输入之一类型)。
但是,获取 TypeInfo
似乎可以使您的特定示例正常工作:
var typeSymbol = semanticModel.GetTypeInfo(compilationUnit // just changed this method
.DescendantNodes().OfType<ClassDeclarationSyntax>().Single()
.Members.OfType<FieldDeclarationSyntax>().Single()
.Declaration.Type);
return typeSymbol.Type.ToDisplayString(new SymbolDisplayFormat(
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameOnly,
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes)); // I'm getting "(int?, double, List)" here
我正在编写一个函数,它接受任何具体的或构造的 Type
,例如 typeof(ValueTuple<Nullable<System.Int32>, double, List<string>>)
和 returns 一个字符串,它是该类型的简化 C# 语法表示(即(int?, double, List<string>)
在这个例子中)。
这是我目前的情况:
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));
}
我正在尝试将几种已知的类型转换方法组合在一起。
- 类型 -> 完全限定名称
- 通过 CodeDOM 的 CSharpCodeProvider.GetTypeOutput
- 完全限定名称 -> TypeSyntax
- 通过 Rosly 的 SyntaxFactory.ParseTypeName
现在我想将 .ToDisplayString()
与几个不同的选项一起使用,但我无法从语义模型中为我的类型找到不为 return null 的类型节点。
如何使用 SymbolDisplayFormat 格式化 TypeSyntax?
此外,我希望这个 将 更改 System.Int32
-> int
,但是,它不会自动修复 [=17] 的实例=] 或 ValueTuple<T1...>
如何执行适当的代码分析规则来替换这些类型名称?
文档状态 GetDeclaredSymbol
仅适用于
any type derived from MemberDeclarationSyntax, TypeDeclarationSyntax, EnumDeclarationSyntax, NamespaceDeclarationSyntax, ParameterSyntax, TypeParameterSyntax, or the alias part of a UsingDirectiveSyntax
你的似乎是 QualifiedNameSyntax
这似乎与预期的输入非常一致,但显然对 Roslyn 意味着其他东西(我承认我没有费心去检查它是否真的继承自预期的输入之一类型)。
但是,获取 TypeInfo
似乎可以使您的特定示例正常工作:
var typeSymbol = semanticModel.GetTypeInfo(compilationUnit // just changed this method
.DescendantNodes().OfType<ClassDeclarationSyntax>().Single()
.Members.OfType<FieldDeclarationSyntax>().Single()
.Declaration.Type);
return typeSymbol.Type.ToDisplayString(new SymbolDisplayFormat(
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameOnly,
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes)); // I'm getting "(int?, double, List)" here