C# Language
Platforma kompilatora .NET (Roslyn)
Szukaj…
Utwórz obszar roboczy z projektu MSBuild
Najpierw uzyskaj nuget Microsoft.CodeAnalysis.CSharp.Workspaces
zanim przejdziesz dalej.
var workspace = Microsoft.CodeAnalysis.MSBuild.MSBuildWorkspace.Create();
var project = await workspace.OpenProjectAsync(projectFilePath);
var compilation = await project.GetCompilationAsync();
foreach (var diagnostic in compilation.GetDiagnostics()
.Where(d => d.Severity == Microsoft.CodeAnalysis.DiagnosticSeverity.Error))
{
Console.WriteLine(diagnostic);
}
Aby załadować istniejący kod do obszaru roboczego, skompiluj i zgłoś błędy. Następnie kod zostanie umieszczony w pamięci. Odtąd dostępna będzie zarówno strona składniowa, jak i semantyczna.
Drzewo składniowe
Drzewo składni to niezmienna struktura danych reprezentująca program jako drzewo nazw, poleceń i znaczników (jak wcześniej skonfigurowano w edytorze).
Załóżmy na przykład, że instancja Microsoft.CodeAnalysis.Compilation
nazwie compilation
została skonfigurowana. Istnieje wiele sposobów wyświetlania nazw wszystkich zmiennych zadeklarowanych w załadowanym kodzie. Aby zrobić to naiwnie, weź wszystkie elementy składni w każdym dokumencie (metoda DescendantNodes
) i użyj Linq, aby wybrać węzły opisujące deklarację zmiennej:
foreach (var syntaxTree in compilation.SyntaxTrees)
{
var root = await syntaxTree.GetRootAsync();
var declaredIdentifiers = root.DescendantNodes()
.Where(an => an is VariableDeclaratorSyntax)
.Cast<VariableDeclaratorSyntax>()
.Select(vd => vd.Identifier);
foreach (var di in declaredIdentifiers)
{
Console.WriteLine(di);
}
}
Każdy typ konstrukcji C # z odpowiednim typem będzie istniał w drzewie składni. Aby szybko znaleźć określone typy, użyj okna Syntax Visualizer
z Visual Studio. Spowoduje to zinterpretowanie bieżącego otwartego dokumentu jako drzewa składniowego Roslyn.
Model semantyczny
Model semantyczny oferuje głębszy poziom interpretacji i wglądu w kod w porównaniu z drzewem składni. Tam, gdzie drzewa składniowe mogą podawać nazwy zmiennych, modele semantyczne podają także typ i wszystkie odwołania. Drzewa składniowe zauważają wywołania metod, ale modele semantyczne podają odniesienia do dokładnej lokalizacji, w której deklarowana jest metoda (po zastosowaniu rozwiązania przeciążenia).
var workspace = Microsoft.CodeAnalysis.MSBuild.MSBuildWorkspace.Create();
var sln = await workspace.OpenSolutionAsync(solutionFilePath);
var project = sln.Projects.First();
var compilation = await project.GetCompilationAsync();
foreach (var syntaxTree in compilation.SyntaxTrees)
{
var root = await syntaxTree.GetRootAsync();
var declaredIdentifiers = root.DescendantNodes()
.Where(an => an is VariableDeclaratorSyntax)
.Cast<VariableDeclaratorSyntax>();
foreach (var di in declaredIdentifiers)
{
Console.WriteLine(di.Identifier);
// => "root"
var variableSymbol = compilation
.GetSemanticModel(syntaxTree)
.GetDeclaredSymbol(di) as ILocalSymbol;
Console.WriteLine(variableSymbol.Type);
// => "Microsoft.CodeAnalysis.SyntaxNode"
var references = await SymbolFinder.FindReferencesAsync(variableSymbol, sln);
foreach (var reference in references)
{
foreach (var loc in reference.Locations)
{
Console.WriteLine(loc.Location.SourceSpan);
// => "[1375..1379)"
}
}
}
}
Spowoduje to wyświetlenie listy zmiennych lokalnych przy użyciu drzewa składni. Następnie konsultuje się z modelem semantycznym, aby uzyskać pełną nazwę typu i znaleźć wszystkie odwołania do każdej zmiennej.