Допустим, у меня есть простой проект
class Program : TestBase
{
static void Main(string[] args)
{
}
public void Test()
{
AddItem(new Item());
AddItem(new Item());
}
}
public class Item { }
public class TestBase
{
public virtual void AddItem(Item vertex) { }
}
Как извлечь AddItem(new Item()); с помощью VSSDK? Я хочу знать, какие параметры ему передаются и в какой строке он находится в текстовом редакторе.
Я пытался найти CodeElement.Kind, но, к сожалению, vsCMElement.vsCMElementFunctionInvokeStmt ничего не возвращает. Есть ли другой способ извлечь эту информацию?
public static async Task InitializeAsync(AsyncPackage package)
{
// ...
_dte = (await package.GetServiceAsync(typeof(DTE))) as DTE2;
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
var sandboxProject = _dte.Solution.Projects;
var codeItems = new List<string>();
if (!ThreadHelper.CheckAccess())
return;
foreach (Project project in sandboxProject)
{
var projectItems = GetProjectItemsRecursively(project.ProjectItems);
foreach (ProjectItem projectItem in projectItems)
{
foreach (CodeElement element in projectItem.FileCodeModel.CodeElements)
{
codeItems.AddRange(GetItems(element).Select(codeItem => $"{codeItem.FullName} : {codeItem.Kind.ToString()}"));
}
}
}
}
private static IEnumerable<CodeElement> GetItems(CodeElement items)
{
var ret = new List<CodeElement>();
if (items == null)
return ret;
foreach (CodeElement item in items.Children)
{
ret.Add(item);
ret.AddRange(GetItems(item));
}
return ret;
}
private static List<ProjectItem> GetProjectItemsRecursively(ProjectItems items)
{
var ret = new List<EnvDTE.ProjectItem>();
if (items == null) return ret;
foreach (ProjectItem item in items)
{
ret.Add(item);
ret.AddRange(GetProjectItemsRecursively(item.ProjectItems));
}
return ret;
}
@HansPassant Спасибо, мой код вернул параметр args для static void Main(string[] args), поэтому я предположил, что он также сможет возвращать вызовы методов внутри метода.
Какая версия Visual Studio?
@SimonMourier Сообщество VS2019





В современной версии Visual Studio, если вы заинтересованы в языковых службах, вам не нужно использовать DTE и старый материал FileCodeModel, но вы можете использовать Пакет SDK для платформы компилятора .NET (также известный как Roslyn), который теперь является основой синтаксического анализа.
Итак, первое, что нужно сделать, это добавить последний пакет nuget Microsoft.CodeAnalysis.CSharp.Workspaces (roslyn для C#) и nuget Microsoft.VisualStudio.LanguageServices (рабочее пространство Visual Studio Roslyn) в проект пакета. Обратите внимание, что вам, возможно, придется исправить обычный беспорядок nuget...
Как только это будет сделано, вы можете написать такой код вместо своего:
// get component model & Visual Studio Roslyn workspace
var componentModel = await package.GetServiceAsync<SComponentModel, IComponentModel>();
var workspace = componentModel.GetService<VisualStudioWorkspace>(); // requires "Microsoft.VisualStudio.LanguageServices" nuget package
// enum all the projects
foreach (var project in workspace.CurrentSolution.Projects)
{
// enum all the documents in the project
foreach (var doc in project.Documents)
{
// get the semantic model & syntax tree root
var model = await doc.GetSemanticModelAsync();
var root = await model.SyntaxTree.GetRootAsync();
// find a class named "TestBase"
// ClassDeclarationSyntax etc. requires "Microsoft.CodeAnalysis.CSharp.Workspaces" nuget package
var myClass = root.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.FirstOrDefault(c => c.Identifier.Text == "TestBase");
if (myClass != null)
{
// find a method named "AddItem"
var myMethod = myClass.Members.Where(m => m.Kind() == SyntaxKind.MethodDeclaration)
.OfType<MethodDeclarationSyntax>()
.FirstOrDefault(m => m.Identifier.Text == "AddItem");
if (myMethod != null)
{
// get the list of method parameters
var parameters = myMethod.ParameterList.Parameters;
...
// get the start line for the method declaration
var lineSpan = model.SyntaxTree.GetLineSpan(myMethod.Span);
int startLine = lineSpan.StartLinePosition.Line;
...
}
}
}
}
Это выглядит красиво, я попробую, как только вернусь домой.
Чтобы знать количество параметров метода, требуется синтаксический анализатор. Так что не VSSDK, у него нет парсера. Такая функция, как подсветка синтаксиса, основана на лексическом анализе. Roslyn — это стандартное решение для анализа кода C#, если вам все равно нужно анализировать только код C# или VB.NET.