Share via


프로젝트 API 쿼리

VisualStudio.Extensibility 프로젝트 쿼리 API를 사용하면 프로젝트 시스템의 정보를 쿼리할 수 있습니다. 프로젝트 시스템은 사용자가 프로젝트를 사용하고 기본 빌드를 실행하여 결과를 생성하고 출력을 테스트하는 데 도움이 되는 Visual Studio 구성 요소의 일부입니다.

프로젝트 쿼리 API의 목표는 다음과 같습니다.

  1. Project Systems 작업
  2. 프로젝트에서 데이터 검색
  3. 프로젝트 변경

프로젝트에 포함된 파일 이해, 프로젝트에서 참조하는 NuGet 패키지, 프로젝트에 새 파일 추가 또는 프로젝트 속성 변경 등이 있습니다.

프로젝트 시스템에 대한 자세한 내용은 여기를 참조하세요. 여기에서 프로젝트 시스템의 개념, 사용량 및 다양한 용어에 대한 개념 설명서를 찾습니다.

프로젝트 쿼리 API 작업

이 개요에서는 프로젝트 쿼리 API를 사용하기 위한 주요 시나리오에 대해 설명합니다.

프로젝트 쿼리 공간에 액세스

프로젝트 시스템을 쿼리하려면 프로젝트 시스템을 쿼리하거나 업데이트하는 여러 비동기 메서드가 있는 프로젝트 쿼리 공간 개체의 인스턴스를 가져와야 합니다. 이 프로젝트 쿼리 공간이라는 용어와 작업 영역이라는 용어는 모두 프로젝트의 모든 데이터에 대한 액세스를 제공하는 동일한 개체를 의미합니다.

Out-of-process 확장의 프로젝트 쿼리 공간 액세스

Out-of-process 확장을 만드는 경우 다음 코드를 사용합니다.

WorkspacesExtensibility workSpace = this.Extensibility.Workspaces();

In-Process 확장의 프로젝트 쿼리 공간 액세스

In-process 확장을 만드는 경우 다음 코드 예제와 같이 프로젝트 쿼리 공간에 액세스합니다. In-process 확장을 특별히 만들지 않은 경우 이전 섹션의 코드 조각을 사용하여 프로젝트 쿼리 공간 개체의 인스턴스를 가져옵니다.

다음 코드 발췌에서 package은(는) Visual Studio 확장 개발에 사용된 클래스인 AsyncPackage의 인스턴스를 나타냅니다. 이 GetServiceAsync 메서드는 Visual Studio의 서비스 컨테이너에서 쿼리 서비스를 비동기적으로 조달하는 데 사용됩니다.

IProjectSystemQueryService queryService = await package.GetServiceAsync<IProjectSystemQueryService, IProjectSystemQueryService>();
ProjectQueryableSpace workSpace = queryService.QueryableSpace;

프로젝트에 대한 프로젝트 시스템 쿼리

개체를 WorkspacesExtensibility 사용하면 프로젝트 GUID가 있는 경우 개별 프로젝트를 쿼리할 수 있습니다. 일반적으로 프로젝트와 연결된 두 개의 GUID가 있습니다. 하나는 프로젝트 형식을 나타내고 다른 하나는 프로젝트를 고유하게 나타냅니다. 솔루션 파일 또는 확장 프로그램에서 프로젝트의 고유 GUID를 찾을 수 있습니다. 다음 섹션에서 설명한 대로 속성을 쿼리 Guid 할 수 있습니다.

IAsyncEnumerable<IQueryResultItem<IProjectSnapshot>> projectList = workspace
    .ProjectsByProjectGuid(knownGuid) 
    .QueryAsync(cancellationToken);

쿼리 결과에 포함할 프로젝트 매개 변수 지정

프로젝트 시스템을 쿼리할 때 절을 사용하여 With 쿼리 결과에 포함되는 매개 변수 또는 메타데이터를 제어할 수 있습니다. 포함해야 하는 매개 변수를 지정하는 몇 가지 유효한 방법이 있습니다.

각 매개 변수에 대해 별도의 With 절을 사용하는 예제

IAsyncEnumerable<IQueryResultItem<IProjectSnapshot>> allProjects = workSpace
    .Projects
    .With(p => p.Path)
    .With(p => p.Guid)
    .With(p => p.Kind)      // DTE.Project.Kind
    .With(p => p.Type)      // VSHPROPID_ProjectType
    .With(p => p.TypeGuid)  // VSHPROPID_TypeGuid
    .With(p => p.Capabilities)
    .QueryAsync(cancellationToken);

    await foreach (IQueryResultItem<IProjectSnapshot> project in allProjects)
    {
        var projectGuid = project.Value.Guid;
        // Checking whether 'Capabilities' property has been retrieved.
        // Otherwise, it can throw for projects which do not support it. (Like SQL projects)
        bool capabilities = project.Value.PropertiesAvailableStatus.Capabilities;
    }

단일 With 절을 사용하여 여러 매개 변수를 지정하는 예제

단일 With 절에서 원하는 매개 변수를 여러 개 지정할 수도 있습니다.

IAsyncEnumerable<IQueryResultItem<IProjectSnapshot>> allProjects = workSpace
    .Projects
    .With(p => new { p.Path, p.Guid, p.Capabilities })
    .QueryAsync(cancellationToken);

절을 WithRequired 사용하는 예제

사용하는 WithRequired경우 필수 속성이 있는 프로젝트만 반환됩니다.

IAsyncEnumerable<IQueryResultItem<IProjectSnapshot>> projectWithFiles = workSpace
    .Projects
    .With(p => new { p.Path, p.Guid })
    .WithRequired(p => p.Files.Where(f => f.FileName == "information.txt"))
    .QueryAsync(cancellationToken);

속성이 지정되지 않은 경우의 예

속성이 지정되지 않은 경우 반환된 기본 속성 집합입니다.

IAsyncEnumerable<IQueryResultItem<IPropertySnapshot>> properties = myproject
    .PropertiesByName("RootNamespace", "AssemblyVersion")
    .QueryAsync(cancellationToken);

이 쿼리 필터 결과입니다.

쿼리 결과를 제한하기 위해 조건부 필터링을 적용하는 Where 두 가지 방법이 있습니다. 문 및 기본 제공 필터링을 사용하는 쿼리 메서드.

절을 Where 사용하는 예제

다양한 프로젝트 유형은 다양한 기능 집합을 지원합니다. 절을 Where 사용하면 특정 기능을 지원하는 프로젝트를 필터링할 수 있습니다. 관련 기능을 지원하는 프로젝트로 필터링하지 않으면 쿼리가 실패할 수 있습니다.

다음 코드는 작업 영역의 모든 .NET Core 웹 프로젝트의 PathGuid을(를) 반환합니다.

IAsyncEnumerable<IQueryResultItem<IProjectSnapshot>> webProjects = workspace
    .Projects
    .Where(p => p.Capabilities.Contains("DotNetCoreWeb"))
    .With(p => new { p.Path, p.Guid })
    .QueryAsync(cancellationToken);

RuleResultsByRuleName 필터링을 사용한 예제

개별 프로젝트 수준에서 각 프로젝트에는 RulesResultsItems을(를) 포함하는 RuleName 특성이 있습니다. API 호출 RuleResultsByRuleName을(를) 사용하여 프로젝트 내의 규칙 유형별로 필터링할 수 있습니다.

    var results = await querySpace
        .Projects
        .With(p => p.Path)
        .With(p => p.ActiveConfigurations
            .With(c => c.RuleResultsByRuleName("CompilerCommandLineArgs")
                .With(r => r.RuleName)
                .With(r => r.Items
                    .With(i => i.Name))))
        .ExecuteQueryAsync();

ProjectsByCapabilities 필터링을 사용한 예제

쿼리에 기본 제공된 필터링이 있는 쿼리 ProjectsByCapabilities 메서드를 사용할 수도 있습니다.

IAsyncEnumerable<IQueryResultItem<IProjectSnapshot>> webProjects = workspace
        .ProjectsByCapabilities("DotNetCoreWeb | DotNetCoreRazor")
        .With(p => new { p.Path, p.Guid })
        .QueryAsync(cancellationToken);

중첩된 쿼리를 사용하여 원하는 속성 지정

일부 매개 변수는 자체 컬렉션이며 중첩된 쿼리를 사용하여 해당 자식 컬렉션에 대해 유사한 사양 및 필터링을 수행할 수 있습니다.

예시

다음 예제에서 중첩된 쿼리를 사용하면 외부 쿼리에서 반환된 각 프로젝트에 포함할 파일 컬렉션을 필터링하고 지정할 수 있습니다.

IAsyncEnumerable<IQueryResultItem<IProjectSnapshot>> projects = workspace
    .ProjectsByCapabilities("CPS")
    .With(p => new { p.Path, p.IsProjectFileSearchable })
    .With(p => p.PropertiesByName("ApplicationIcon")) // Retrieve a single property, if it exists
    .With(p => p.Files // Without any condition, retrieve all files in the project, but filter them
        .Where(f => f.Extension == ".ico")
        .With(f => new { f.Path, f.IsHidden }))
    .QueryAsync(cancellationToken);

    await foreach (IQueryResultItem<IProjectSnapshot> project in projects)
    {
        IPropertySnapshot property = project.Value.Properties.FirstOrDefault();
        string? applicationIcon = (string?)property?.Value;

        foreach (var iconFile in project.Value.Files)
        {
            string filePath = iconFile.Path;
            bool isHidden = iconFile.IsHidden;
        }
    }

Get 메서드를 사용하여 자식 컬렉션 검색

Visual Studio 프로젝트 모델에는 프로젝트 및 자식 컬렉션(예: 프로젝트 내의 파일 또는 프로젝트 기능)에 대한 컬렉션이 있습니다. 자식 컬렉션 자체를 검색하려면 절을 Get 사용할 수 있습니다. 다른 쿼리 형식과 마찬가지로 절을 Get 사용하면 절과 같은 With 다른 절을 사용하여 결과를 셰이프하거나 제한할 수 있습니다.

IAsyncEnumerable<IQueryResultItem<IFileSnapshot>> files = workspace
    .Projects
    .Where(p => p.Guid == knownGuid)
    .Get(p => p.Files
        .With(f => new { f.Path, f.IsHidden, f.IsSearchable }))
    .QueryAsync(cancellationToken);

    await foreach (var file in files)
    {
        string filePath = file.Value.Path;
    }

이전에 반환된 항목에서 추가 정보 쿼리

이전 쿼리의 결과를 추가 쿼리의 기반으로 사용할 수 있습니다.

IAsyncEnumerable<IQueryResultItem<IProjectSnapshot>> allProjects = workSpace
    .Projects
    .With(p => p.Path)
    .With(p => p.Guid)
    .QueryAsync(cancellationToken);

await foreach (IQueryResultItem<IProjectSnapshot> project in allProjects)
{
    // Gets child collections
    IAsyncEnumerable<IQueryResultItem<IFileSnapshot>> files = project.Value
        .Files
        .With(f => new { f.Path, f.ItemType })
        .QueryAsync(cancellationToken);
}

프로젝트 수정

쿼리 결과는 일반적으로 변경할 수 없습니다. 또한 쿼리 API를 사용하여 절을 사용하여 AsUpdatable 변경하여 변경 가능한 버전의 쿼리 결과에 액세스할 수 있으므로 프로젝트 및 프로젝트 항목을 변경할 수 있습니다.

쿼리 결과에서 프로젝트에 파일을 추가하는 예제

IQueryResult<IProjectSnapshot> updatedProjects = workSpace
    .ProjectsByProjectGuid(knownGuid)
    .AsUpdatable()
    .CreateFile("AdditionalInformation.txt", textContent)
    .ExecuteAsync(cancellationToken);

이전에 반환된 프로젝트에 파일을 추가하는 예제

IQueryResult<IProjectSnapshot> updatedProjects = myproject
    .AsUpdatable()
    .CreateFile("AdditionalInformation2.txt", textContent)
    .ExecuteAsync(cancellationToken);

프로젝트 이름 바꾸기 예제

IQueryResult<IProjectSnapshot> updatedProjects = myproject
    .AsUpdatable()
    .Rename("NewProjectName", textContent)
    .ExecuteAsync(cancellationToken);

프로젝트 속성 쿼리

Get 절을 사용하여 프로젝트 속성을 쿼리할 수 있습니다. 다음 쿼리는 요청된 두 속성에 대한 항목을 포함하는 IPropertySnapshot 컬렉션을 반환합니다. IPropertySnapshot에는 특정 시점의 속성 이름, 표시 이름 및 값이 포함됩니다.

// We assume that we can find the "RootNamespace" property in the result.
// However it isn't true from query API point of view.
// The query tries to retrieve items based on the condition, and if there is no such item, it will run successfully, only without returning items.
IAsyncEnumerable<IQueryResultItem<IPropertySnapshot>> properties = myProject
    .AsQueryable()  
    .Get(p => p.PropertiesByName("RootNamespace", "AssemblyVersion"))
    .QueryAsync(cancellationToken);

솔루션 쿼리

앞서 설명한 대로 프로젝트 작업 외에도 비슷한 기술을 사용하여 솔루션을 사용할 수 있습니다.

IAsyncEnumerable<IQueryResultItem<ISolutionSnapshot>> solutions = workSpace
    .Solutions
    .With(s => new { s.Path, s.Guid, s.ActiveConfiguration, s.ActivePlatform })
    .QueryAsync(cancellationToken);

솔루션 폴더 쿼리

마찬가지로 Get 절을 사용하여 솔루션 폴더를 쿼리할 수 있습니다. 이 IsNested 속성을 사용하면 결과에서 중첩된 폴더를 포함하거나 제외할 수 있습니다. 솔루션 탐색기 구성 설정 또는 리소스와 같은 중첩된 폴더를 가질 수 있습니다.

IAsyncEnumerable<IQueryResultItem<ISolutionFolderSnapshot>> solutionFolders = workSpace
    .Solutions
    .Get(s => s.SolutionFolders)
    .With(folder => folder.Name)
    .With(folder => folder.IsNested)
    .With(folder => folder.VisualPath) // it's a relative (virtual) path to represent how the folder is nested.
    .QueryAsync(cancellationToken);

이 예제에서는 솔루션 폴더 내에 중첩된 모든 솔루션 폴더, 프로젝트, 파일을 가져옵니다(재귀적으로 중첩되지 않음).

IAsyncEnumerable<IQueryResultItem<ISolutionSnapshot>> solutionFoldersWithExtraInformation = mySolutionFolder
    .AsQueryable()
    .With(folder => folder.Files
        .With(f => f.Path))
    .With(folder => folder.Projects
        .With(p => new { p.Name, p.Guid }))
    .With(folder => folder.SolutionFolders
        .With(nested => nested.Name))
    .QueryAsync(cancellationToken);

이 예제에서는 재귀적으로 중첩된 솔루션 폴더를 모두 가져옵니다. VisualPath는 솔루션 탐색기에 표시되는 경로입니다.

string visualPath = mySolutionFolder.VisualPath;
IAsyncEnumerable<IQueryResultItem<ISolutionFolderSnapshot>> recursivelyNestedFolders = await workSpace
    .Solutions
    .Get(s => s.SolutionFolders)
    .Where(f => f.VisualPath.StartsWith(visualPath) && f.VisualPath != visualPath)
    .With(f => f.Name)
    .QueryAsync(cancellationToken);

프로젝트의 추가 정보를 사용하여 원본 파일 열거

다음은 프로젝트의 모든 .xaml 파일과 해당 코드 생성기를 열거하는 예제입니다.

IAsyncEnumerable<IQueryResultItem<IFileSnapshot>> files =
workSpace.ProjectsByProjectGuid(knownGuid)
    .Get(p => p.Files)
    .Where(file => file.Extension == ".xaml")
    .With(file => file.Path)
    .With(file => file.PropertiesByName("Generator"))
    .QueryAsync(cancellationToken);

또 다른 예는 이전 쿼리에서 반환된 프로젝트로 시작하는 것입니다.

IAsyncEnumerable<IQueryResultItem<IFileSnapshot>> files = myProject
    .FilesEndingWith(".xaml")     // use built-in filter instead of 'Where' condition
    .With(file => file.Path)
    .With(file => file.PropertiesByName("Generator"))
    .QueryAsync(cancellationToken);

또는 HTML 및 CSS 파일과 같이 런타임에 필요한 컴파일되지 않은 파일인 모든 콘텐츠 파일을 가져옵니다.

IAsyncEnumerable<IQueryResultItem<IFileSnapshot>> files =
    myProject.FilesWithItemTypes("Content")
        .With(file => file.Path)
        .QueryAsync(cancellationToken);

또는 모든 프로젝트의 XML 스키마 파일(.xsd 파일)과 같은 특정 확장명으로 모든 파일을 열거하려면 다음을 수행합니다.

IAsyncEnumerable<IQueryResultItem<IFileSnapshot>> schemaFiles =
workSpace.Projects
    .Get(proj => proj.FilesEndingWith(".xsd"))
    .With(file => file.Path)
    .QueryAsync(cancellationToken);

    await foreach (IQueryResultItem<IFileSnapshot> fileResult in schemaFiles)
    {
        DoSomething(fileResult.Value.Path);
    }

특정 원본 파일을 소유한 프로젝트 쿼리

프로젝트 및 폴더에는 자신이 소유하거나 포함하는 파일에 대한 정보가 있으므로 절을 WithRequired 사용하여 특정 파일이 포함된 프로젝트를 쿼리할 수 있습니다.

지정된 파일을 소유한 프로젝트 찾기의 예

IAsyncEnumerable<IQueryResultItem<IProjectSnapshot>> projects = workspace
    .Projects
    .WithRequired(proj => proj.FilesByPath(myFilePath))
    .With(proj => proj.Guid)
    .QueryAsync(cancellationToken);

지정된 파일이 포함된 솔루션 폴더를 찾는 예제

IAsyncEnumerable<IQueryResultItem<ISolutionFolderSnapshot>> solutionFolders = workspace
    .Solutions
    .Get(s => s.SolutionFolders)
    .WithRequired(folder => folder.FilesByPath(myFilePath))
    .With(folder => folder.Name)
    .With(folder => folder.Guid)
    .QueryAsync(cancellationToken);

프로젝트 구성 및 해당 속성에 대한 쿼리Query for project configuration and their properties

프로젝트에는 ConfigurationDimension 프로젝트 구성 정보를 찾는 데 사용할 수 있는 속성이 있습니다. 프로젝트 구성 정보는 프로젝트 빌드 구성(예 Debug : 및)과 Release관련이 있습니다.

IAsyncEnumerable<IQueryResultItem<IProjectSnapshot>> projects = workspace
    .Projects
    .With(p => new { p.Guid, p.Name })
    .With(p => p.Configurations
        .With(c => c.Name)
        .With(c => c.PropertiesByName("OutputPath"))
        .With(c => c.ConfigurationDimensions)) // ConfigurationDimension is essentially Name, Value pairs, both are default properties.
    .QueryAsync(cancellationToken);

    await foreach (IQueryResultItem<IProjectSnapshot> project in projects)
    {
        foreach (var configuration in project.Value.Configuration)
        {
            // ...
        }
    }

모든 프로젝트 간 쿼리

쿼리하여 지정된 프로젝트를 참조하는 프로젝트를 찾을 수도 있습니다.

현재 프로젝트에서 참조하는 모든 프로젝트를 찾는 예제

IAsyncEnumerable<IQueryResultItem<IProjectReferenceSnapshot>> projectReferences = myProject
    .ProjectReferences
    .With(r => r.ProjectGuid)
    .With(r => r.ReferencedProjectId)
    .QueryAsync(cancellationToken);

현재 프로젝트를 참조하는 모든 프로젝트를 찾는 예제

IAsyncEnumerable<IQueryResultItem<IProjectSnapshot>> projects = workSpace
    .Projects
    .With(p => p.Guid)
    .WithRequired(p => p.ProjectReferences
        .Where(r => r.ProjectGuid == knownGuid))
    .QueryAsync(cancellationToken);

패키지 참조 쿼리

마찬가지로 NuGet 패키지 참조를 쿼리할 수 있습니다.

현재 프로젝트에서 참조하는 모든 패키지를 찾는 예제

IAsyncEnumerable<IQueryResultItem<IProjectConfigurationSnapshot>> configurationsWithPackageReferences = myProject
    .ActiveConfigurations
    .With(c => c.Name)
    .With(c => c.PackageReferences
        .With(p => new { p.Name, p.Version }))
    .QueryAsync(cancellationToken);

특정 NuGet 패키지를 참조하는 모든 프로젝트를 찾는 예제

string packageName = "Newtonsoft.Json";

IAsyncEnumerable<IQueryResultItem<IProjectSnapshot>> projects = workSpace
    .Projects
    .With(p => p.Guid)
    .WithRequired(p => p.ActiveConfigurations
        .WithRequired(c => c.PackageReferences
            .Where(package => package.Name == packageName)))
    .QueryAsync(cancellationToken);

프로젝트 출력 그룹에 대한 쿼리

프로젝트 구성에는 프로젝트 출력 그룹에 대한 정보가 있습니다.

// From our list of active configurations, we need to get the first one in the list
IAsyncEnumerable<IQueryResultItem<IProjectConfigurationSnapshot>> configurations = myProject
    .ActiveConfigurations
    .QueryAsync(cancellationToken);

    IProjectConfigurationSnapshot myConfiguration = null;

    await foreach (IQueryResultItem<IProjectConfigurationSnapshot> config in configurations)
    {
        myConfiguration = config.Value;
        break;
    }

    // A multi-target project may have multiple active configurations
    IAsyncEnumerable<IQueryResultItem<IOutputGroupSnapshot>> outputGroups = myConfiguration
        .OutputGroupsByName("Built", "Symbols")
        .With(g => g.Name)
        .With(g => g.Outputs)
        .QueryAsync(cancellationToken);

시작 프로젝트 쿼리

솔루션에는 실행 파일로 실행할 수 있는 시작 프로젝트 집합이 있습니다.

// A query to get the list of startup project's name and path
var result = await this.QueryableSpace.Solutions
    .With(solution => solution.StartupProjects
        .With(startupproject => startupproject.Name)
        .With(startupproject => startupproject.Path))
    .QueryAsync(CancellationToken.None);

시작 프로젝트를 설정하는 작업

프로젝트 쿼리 API를 사용하여 실행할 프로젝트를 선택할 수도 있습니다. 아래 샘플에서는 두 개의 프로젝트 경로를 시작 프로젝트로 설정하는 방법을 보여 줍니다.

// A query to set the startup project
var result = await this.QueryableSpace.Solutions
        .With(solution => solution.StartupProjects)
        .AsUpdatable()
        .SetStartupProjects("full\\path\\to\\project1.csproj", 
                            "full\\path\\to\\project2.csproj")
    .ExecuteAsync(CancellationToken.None);

솔루션 구성 쿼리

솔루션 구성은 구성이 활성화 상태일 때 빌드에 포함되는 프로젝트 컬렉션입니다. 아래 예제에서는 솔루션 구성의 이름을 쿼리하는 방법을 보여 줍니다.

var results = await this.Extensibility.Workspaces().QuerySolutionAsync(
    solution => solution.With(solution => solution.SolutionConfigurations
    .With(c => c.Name)),
    cancellationToken);

솔루션 구성 추가 예제

AddSolutionConfiguration 메서드는 다음 세 개의 매개 변수를 사용합니다.

  1. 첫 번째 매개 변수는 새 솔루션 구성의 새 이름입니다. 이 예제에서는 새 솔루션 구성을 Foo라고 합니다.
  2. 다음 매개 변수는 새 구성을 기반으로 하는 구성입니다. 아래에서 새 솔루션 구성은 기존 솔루션 구성 Debug을(를) 기반으로 합니다.
  3. 마지막으로 부울은 솔루션 구성을 전파해야 하는지 여부를 나타냅니다.
await this.Extensibility.Workspaces().UpdateSolutionAsync(
    solution => solution.Where(solution => solution.BaseName == "mySolution"),
    solution => solution.AddSolutionConfiguration("Foo", "Debug", false),
    cancellationToken);

솔루션 구성 삭제 예제

DeleteSolutionConfiguration는 솔루션 구성을 제거하는 API 호출입니다. 아래 예제에서는 Foo라는 솔루션 구성이 제거됩니다.

await this.Extensibility.Workspaces().UpdateSolutionAsync(
    solution => solution.Where(solution => solution.BaseName == "mySolution"),
    solution => solution.DeleteSolutionConfiguration("Foo"),
    cancellationToken);

프로젝트를 로드/언로드하는 작업 쿼리

프로젝트를 언로드해야 하는 경우 솔루션을 지정하고 언로드하려는 프로젝트의 경로를 지정해야 합니다. 아래 예제에서는 Extensibility.Workspaces().UpdateSolutionAsync 메서드를 사용하여 솔루션을 업데이트하고 UnloadProject를 사용하여 프로젝트를 언로드합니다.

await this.Extensibility.Workspaces().UpdateSolutionAsync(
    solution => solution.Where(solution => solution.BaseName == "MySolution"),
    solution => solution.UnloadProject("full\\path\\to\\project.csproj"),
    cancellationToken);

AsUpdatable은(는) 프로젝트를 로드하거나 언로드하는 데에도 사용할 수 있습니다.

var result = await querySpace.Solutions
    .AsUpdatable()
    .LoadProject("full\\path\\to\\project.csproj")
    .ExecuteAsync();

솔루션/프로젝트를 빌드하는 작업 쿼리

프로젝트 쿼리에서는 프로젝트 또는 솔루션 수준에서 빌드 작업을 호출하는 기능도 있습니다. 이러한 빌드 작업에는 다음이 포함됩니다.

  • BuildAsync
  • RebuildAsync
  • CleanAsync
  • DebugLaunchAsync
  • LaunchAsync

솔루션 수준 빌드

솔루션 수준에서 빌드하면 솔루션에 로드되는 모든 프로젝트가 빌드됩니다. 다음은 솔루션을 빌드하는 예제입니다.

var result = await querySpace.Solutions
        .BuildAsync(cancellationToken);

프로젝트 수준에서 빌드

프로젝트 수준에서 빌드하는 동안 빌드하려고 선택한 프로젝트를 결정합니다. 아래 예제에서 myProject가 빌드될 IProjectSnapshot입니다.

 var result = await myProject.BuildAsync(cancellationToken);

솔루션/프로젝트를 저장하는 작업 쿼리

SaveAsync는 프로젝트 또는 솔루션 수준에서 사용할 수 있습니다.

솔루션 수준에서 저장

var result = await querySpace.Solutions
        .SaveAsync(cancellationToken);

프로젝트 수준에서 저장

myProject는 저장할 대상 프로젝트의 IProjectSnapshot입니다.

 var result = await myProject.SaveAsync(cancellationToken);

쿼리 변경 내용을 추적하는 작업 쿼리

TrackUpdatesAsync는 프로젝트 또는 솔루션 수준에서 사용할 수 있습니다. 프로젝트 또는 솔루션의 변경 내용을 추적하는 데 사용됩니다.

이 예제에서는 파일 이름 필터가 적용된 프로젝트의 Files 속성에서 TrackUpdatesAsync가 호출됩니다. 즉, 프로젝트의 파일 이름 변경 내용을 추적합니다. TrackerObserver 인스턴스는 변경 알림을 받도록 전달됩니다.

var projects = await querySpace.Projects.ExecuteQueryAsync(cancellationToken: CancellationToken.None);

var singleProject = projects.FirstOrDefault();
 
var unsubscriber = await singleProject
    .Files
    .With(f => f.FileName)
    .TrackUpdatesAsync(new TrackerObserver(), CancellationToken.None);

특히 TrackerObserverIQueryTrackUpdates<IFileSnapshot>에 대한 IObserver 인터페이스를 구현하는 비공개 클래스입니다. 이는 파일 스냅샷 업데이트 추적에 대한 알림을 받도록 설계되었습니다.

private class TrackerObserver : IObserver<IQueryTrackUpdates<IFileSnapshot>>
{
    public void OnCompleted()
    {
        ...
    }
 
    public void OnError(Exception error)
    {
        ...
    }
 
    public void OnNext(IQueryTrackUpdates<IFileSnapshot> value)
    {
        ...
    }
 
    public override int GetHashCode()
    {
        ...
    }
}

건너뛸 작업 쿼리

Skip은 쿼리에서 N개의 결과를 건너뛰는 데 사용할 수 있습니다.

이 코드 샘플에서는 쿼리의 첫 번째 결과를 건너뜁습니다. 예를 들어 솔루션에 3개의 프로젝트가 있는 경우 첫 번째 결과는 건너뛰고 쿼리는 나머지 2개의 프로젝트를 반환합니다. 참고: 주문은 보장되지 않습니다.

var projects = await queryableSpace.Projects
        .With(proj => proj.Name)
        .Skip(1)
       .ExecuteQueryAsync(new CancellationToken());

다음 단계

프로젝트 쿼리 API에 대한 키워드(keyword) 및 개념을 검토하려면 프로젝트 쿼리 개념을 참조하세요.

VSProjectQueryAPISample에서 프로젝트 쿼리 API를 사용하는 확장에 대한 코드를 검토합니다.