다음을 통해 공유


RoslynCodeTaskFactory를 사용하여 MSBuild 인라인 작업 만들기

RoslynCodeTaskFactory 는 플랫폼 간 Roslyn 컴파일러를 사용하여 인라인 작업으로 사용할 메모리 내 태스크 어셈블리를 생성합니다. RoslynCodeTaskFactory 작업은 .NET Standard를 대상으로 하며 Linux 및 macOS와 같은 다른 플랫폼뿐만 아니라 .NET Framework 및 .NET Core 런타임에서도 작동할 수 있습니다.

비고

RoslynCodeTaskFactory는 MSBuild 15.8 이상에서만 사용할 수 있습니다. MSBuild 버전은 Visual Studio 버전을 따르므로 RoslynCodeTaskFactory는 Visual Studio 2017 버전 15.8 이상에서 사용할 수 있습니다.

RoslynCodeTaskFactory를 사용하는 인라인 작업의 구조

RoslynCodeTaskFactory 인라인 작업은 요소를 사용하여 선언됩니다 UsingTask . 인라인 작업 및 UsingTask 인라인 작업이 포함된 요소는 일반적으로 파일에 포함 .targets 되고 필요에 따라 다른 프로젝트 파일로 가져옵니다. 기본 인라인 작업은 다음과 같습니다. 아무 것도 수행하지 않습니다.

<Project>
  <!-- This simple inline task does nothing. -->
  <UsingTask
    TaskName="DoNothing"
    TaskFactory="RoslynCodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
    <ParameterGroup />
    <Task>
      <Reference Include="" />
      <Using Namespace="" />
      <Code Type="Fragment" Language="cs">
      </Code>
    </Task>
  </UsingTask>
</Project>

UsingTask 이 예제의 요소에는 태스크와 이를 컴파일하는 인라인 작업 팩터리를 설명하는 세 가지 특성이 있습니다.

  • 이 경우 DoNothing특성은 TaskName 작업의 이름을 지정합니다.

  • 이 특성은 TaskFactory 인라인 작업 팩터리를 구현하는 클래스의 이름을 지정합니다.

  • 이 특성은 AssemblyFile 인라인 작업 팩터리의 위치를 제공합니다. 또는 특성을 사용하여 AssemblyName 일반적으로 GAC(전역 어셈블리 캐시)에 있는 인라인 작업 팩터리 클래스의 정규화된 이름을 지정할 수 있습니다.

작업의 나머지 요소는 DoNothing 비어 있으며 인라인 작업의 순서와 구조를 설명하기 위해 제공됩니다. 이 문서의 뒷부분에서 보다 강력한 예제를 제공합니다.

  • ParameterGroup 요소는 선택적입니다. 지정하면 작업에 대한 매개 변수를 선언합니다. 입력 및 출력 매개 변수에 대한 자세한 내용은 이 문서의 뒷부분에 있는 입력 및 출력 매개 변수 를 참조하세요.

  • 요소는 Task 작업 소스 코드를 설명하고 포함합니다.

  • 요소는 Reference 코드에서 사용 중인 .NET 어셈블리에 대한 참조를 지정합니다. Visual Studio에서 프로젝트에 대한 참조를 추가하는 것과 같습니다. 이 특성은 Include 참조된 어셈블리의 경로를 지정합니다.

  • 요소 Using 에는 액세스하려는 네임스페이스가 나열됩니다. 이 요소는 Visual C#의 using 지시문과 유사합니다. 특성은 Namespace 포함할 네임스페이스를 지정합니다.

ReferenceUsing 요소는 언어에 구애받지 않습니다. 인라인 작업은 지원되는 .NET CodeDom 언어(예: Visual Basic 또는 Visual C#) 중 하나로 작성할 수 있습니다.

비고

요소에 Task 포함된 요소는 작업 팩터리(이 경우 코드 작업 팩터리)에 따라 다릅니다.

Code 요소

요소 내에 Task 표시되는 마지막 자식 요소는 요소입니다 Code . 요소는 Code 작업으로 컴파일할 코드를 포함하거나 찾습니다. 요소에 입력한 Code 내용은 작업을 작성하는 방법에 따라 달라집니다.

이 특성은 Language 코드가 작성되는 언어를 지정합니다. 허용되는 값은 cs Visual Basic의 경우 C# vb 입니다.

특성은 Type 요소에 있는 코드의 형식을 Code 지정합니다.

  • TypeClass면 요소에 Code 인터페이스에서 파생되는 클래스에 대한 코드가 ITask 포함됩니다.

  • TypeMethod면 코드는 인터페이스 메서드의 재정의를 ExecuteITask 정의합니다.

  • Type 이면 코드는 Fragment메서드의 Execute 내용을 정의하지만 서명이나 return 문은 정의하지 않습니다.

코드 자체는 일반적으로 표식과 ]]> 표식 사이에 <![CDATA[ 나타납니다. 코드는 CDATA 섹션에 있으므로 예약된 문자(예: "" 또는 "<>")를 이스케이프하는 것에 대해 걱정할 필요가 없습니다.

또는 요소의 Code 특성을 사용하여 Source 작업에 대한 코드가 포함된 파일의 위치를 지정할 수 있습니다. 소스 파일의 코드는 특성에 지정된 Type 형식이어야 합니다. 특성이 Source 있으면 기본값 Type 은 .입니다 Class. 없는 경우 Source 기본값은 .입니다 Fragment.

비고

소스 파일에서 작업 클래스를 정의하는 경우 클래스 이름은 해당 UsingTask 요소의 특성에 TaskName 동의해야 합니다.

전 세계 여러분 안녕하세요

다음은 .를 사용하는 보다 강력한 인라인 작업입니다 RoslynCodeTaskFactory. HelloWorld 작업은 일반적으로 시스템 콘솔 또는 Visual Studio 출력 창인 기본 오류 로깅 디바이스에 "Hello, world!"를 표시합니다. Reference 예제의 요소는 그림에만 포함됩니다.

<Project>
  <!-- This simple inline task displays "Hello, world!" -->
  <UsingTask
    TaskName="HelloWorld"
    TaskFactory="RoslynCodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
    <ParameterGroup />
    <Task>
      <Reference Include="System.Xml"/>
      <Using Namespace="System"/>
      <Using Namespace="System.IO"/>
      <Code Type="Fragment" Language="cs">
<![CDATA[
// Display "Hello, world!"
Log.LogError("Hello, world!");
]]>
      </Code>
    </Task>
  </UsingTask>
</Project>

HelloWorld.targets라는 파일에 작업을 저장 HelloWorld 한 다음 프로젝트에서 다음과 같이 호출할 수 있습니다.

<Project>
  <Import Project="HelloWorld.targets" />
  <Target Name="Hello">
    <HelloWorld />
  </Target>
</Project>

입력 및 출력 매개 변수

인라인 작업 매개 변수는 요소의 자식 요소입니다 ParameterGroup . 모든 매개 변수는 해당 매개 변수를 정의하는 요소의 이름을 사용합니다. 다음 코드는 매개 변수 Text를 정의합니다.

<ParameterGroup>
    <Text />
</ParameterGroup>

매개 변수에는 다음 특성 중 하나 이상이 있을 수 있습니다.

  • Required 는 기본적으로 선택적 특성입니다 false . 이면 true매개 변수가 필요하며 작업을 호출하기 전에 값을 지정해야 합니다.

  • ParameterType 는 기본적으로 선택적 특성입니다 System.String . System.Convert.ChangeType을 사용하여 문자열에서 변환할 수 있는 항목 또는 값인 정규화된 형식으로 설정할 수 있습니다. 즉, 외부 작업으로 전달될 수 있는 모든 형식입니다.

  • Output 는 기본적으로 선택적 특성입니다 false . 이 경우 trueExecute 메서드에서 반환하기 전에 매개 변수에 값을 지정해야 합니다.

예를 들면 다음과 같습니다.

<ParameterGroup>
    <Expression Required="true" />
    <Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
    <Tally ParameterType="System.Int32" Output="true" />
</ParameterGroup>

는 다음 세 가지 매개 변수를 정의합니다.

  • Expression 는 System.String 형식의 필수 입력 매개 변수입니다.

  • Files 는 필수 항목 목록 입력 매개 변수입니다.

  • Tally 는 System.Int32 형식의 출력 매개 변수입니다.

요소에 Code 특성 FragmentType 있는 Method경우 모든 매개 변수에 대해 속성이 자동으로 만들어집니다. RoslynCodeTaskFactory에서 요소 Type 에 특성이 있는 경우 Code 소스 코드에서 유추되므로(이 값과는 다릅니다CodeTaskFactory)을 지정할 ParameterGroup필요가 Class없습니다. 그렇지 않으면 속성이 작업 소스 코드에서 명시적으로 선언되어야 하며 해당 매개 변수 정의와 정확히 일치해야 합니다.

예시

다음 인라인 작업은 일부 메시지를 기록하고 문자열을 반환합니다.

<Project>

    <UsingTask TaskName="MySample"
               TaskFactory="RoslynCodeTaskFactory"
               AssemblyFile="$(MSBuildBinPath)\Microsoft.Build.Tasks.Core.dll">
        <ParameterGroup>
            <Parameter1 ParameterType="System.String" Required="true" />
            <Parameter2 ParameterType="System.String" />
            <Parameter3 ParameterType="System.String" Output="true" />
        </ParameterGroup>
        <Task>
            <Using Namespace="System" />
            <Code Type="Fragment" Language="cs">
              <![CDATA[
              Log.LogMessage(MessageImportance.High, "Hello from an inline task created by Roslyn!");
              Log.LogMessageFromText($"Parameter1: '{Parameter1}'", MessageImportance.High);
              Log.LogMessageFromText($"Parameter2: '{Parameter2}'", MessageImportance.High);
              Parameter3 = "A value from the Roslyn CodeTaskFactory";
            ]]>
            </Code>
        </Task>
    </UsingTask>

    <Target Name="Demo">
      <MySample Parameter1="A value for parameter 1" Parameter2="A value for parameter 2">
          <Output TaskParameter="Parameter3" PropertyName="NewProperty" />
      </MySample>

      <Message Text="NewProperty: '$(NewProperty)'" />
    </Target>
</Project>

이러한 인라인 작업은 경로를 결합하고 파일 이름을 가져올 수 있습니다.

<Project>

    <UsingTask TaskName="PathCombine"
               TaskFactory="RoslynCodeTaskFactory"
               AssemblyFile="$(MSBuildBinPath)\Microsoft.Build.Tasks.Core.dll">
        <ParameterGroup>
            <Paths ParameterType="System.String[]" Required="true" />
            <Combined ParameterType="System.String" Output="true" />
        </ParameterGroup>
        <Task>
            <Using Namespace="System" />
            <Code Type="Fragment" Language="cs">
            <![CDATA[
            Combined = Path.Combine(Paths);
            ]]>
            </Code>
        </Task>
    </UsingTask>

    <UsingTask TaskName="PathGetFileName"
             TaskFactory="RoslynCodeTaskFactory"
             AssemblyFile="$(MSBuildBinPath)\Microsoft.Build.Tasks.Core.dll">
        <ParameterGroup>
            <Path ParameterType="System.String" Required="true" />
            <FileName ParameterType="System.String" Output="true" />
        </ParameterGroup>
        <Task>
            <Using Namespace="System" />
            <Code Type="Fragment" Language="cs">
            <![CDATA[
            FileName = System.IO.Path.GetFileName(Path);
            ]]>
            </Code>
        </Task>
    </UsingTask>

    <Target Name="Demo">
        <PathCombine Paths="$(Temp);MyFolder;$([System.Guid]::NewGuid()).txt">
            <Output TaskParameter="Combined" PropertyName="MyCombinedPaths" />
        </PathCombine>

        <Message Text="Combined Paths: '$(MyCombinedPaths)'" />

        <PathGetFileName Path="$(MyCombinedPaths)">
            <Output TaskParameter="FileName" PropertyName="MyFileName" />
        </PathGetFileName>

        <Message Text="File name: '$(MyFileName)'" />
    </Target>
</Project>

이전 버전과의 호환성 제공

RoslynCodeTaskFactory 먼저 MSBuild 버전 15.8에서 사용할 수 있게 되었습니다. 사용할 수 없지만 CodeTaskFactory 동일한 빌드 스크립트를 사용하려는 경우 RoslynCodeTaskFactory 이전 버전의 Visual Studio 및 MSBuild를 지원하려는 경우를 가정해 보겠습니다. 다음 예제와 같이 속성을 사용하는 구문을 사용하여 Choose$(MSBuildVersion) 빌드 시 사용 여부를 RoslynCodeTaskFactoryCodeTaskFactory결정할 수 있습니다.

<Project Sdk="Microsoft.NET.Sdk" DefaultTargets="RunTask">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>

  <Choose>
    <When Condition=" '$(MSBuildVersion.Substring(0,2))' >= 16 Or
    ('$(MSBuildVersion.Substring(0,2))' == 15 And '$(MSBuildVersion.Substring(3,1))' >= 8)">
      <PropertyGroup>
        <TaskFactory>RoslynCodeTaskFactory</TaskFactory>
      </PropertyGroup>
    </When>
    <Otherwise>
      <PropertyGroup>
        <TaskFactory>CodeTaskFactory</TaskFactory>
      </PropertyGroup>
    </Otherwise>
  </Choose>
  
  <UsingTask
    TaskName="HelloWorld"
    TaskFactory="$(TaskFactory)"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
    <ParameterGroup />
    <Task>
      <Using Namespace="System"/>
      <Using Namespace="System.IO"/>
      <Code Type="Fragment" Language="cs">
        <![CDATA[
         Log.LogError("Using RoslynCodeTaskFactory");
      ]]>
      </Code>
    </Task>
  </UsingTask>

  <Target Name="RunTask" AfterTargets="Build">
    <Message Text="MSBuildVersion: $(MSBuildVersion)"/>
    <Message Text="TaskFactory: $(TaskFactory)"/>
    <HelloWorld />
  </Target>

</Project>