Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
RoslynCodeTaskFactory usa os compiladores Roslyn de plataforma cruzada para gerar assemblies de tarefas na memória para uso como tarefas embutidas.
RoslynCodeTaskFactory as tarefas destinam-se ao .NET Standard e podem funcionar em tempos de execução do .NET Framework e do .NET Core, bem como em outras plataformas, como Linux e macOS.
Observação
O RoslynCodeTaskFactory está disponível apenas no MSBuild 15.8 e superior. As versões do MSBuild seguem as versões do Visual Studio, portanto, RoslynCodeTaskFactory está disponível no Visual Studio 2017 versão 15.8 e superior.
A estrutura de uma tarefa embutida com RoslynCodeTaskFactory
RoslynCodeTaskFactory As tarefas embutidas são declaradas usando o UsingTask elemento . A tarefa embutida e o UsingTask elemento que a contém normalmente são incluídos em um .targets arquivo e importados para outros arquivos de projeto, conforme necessário. Aqui está uma tarefa básica em linha. Note que não faz nada.
<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>
O UsingTask elemento no exemplo tem três atributos que descrevem a tarefa e a fábrica de tarefas embutida que a compila.
O
TaskNameatributo nomeia a tarefa, neste caso,DoNothing.O
TaskFactoryatributo nomeia a classe que implementa a fábrica de tarefas embutidas.O
AssemblyFileatributo fornece o local da fábrica de tarefas embutidas. Como alternativa, você pode usar oAssemblyNameatributo para especificar o nome totalmente qualificado da classe de fábrica de tarefas embutidas, que normalmente está localizada no cache de assembly global (GAC).
Os elementos restantes da DoNothing tarefa estão vazios e são fornecidos para ilustrar a ordem e a estrutura de uma tarefa embutida. Um exemplo mais robusto é apresentado mais adiante neste artigo.
O
ParameterGroupelemento é opcional. Quando especificado, ele declara os parâmetros para a tarefa. Para obter mais informações sobre parâmetros de entrada e saída, consulte Parâmetros de entrada e saída mais adiante neste artigo.O
Taskelemento descreve e contém o código-fonte da tarefa.O
Referenceelemento especifica referências aos assemblies .NET que você está usando em seu código. Isso é equivalente a adicionar uma referência a um projeto no Visual Studio. OIncludeatributo especifica o caminho do assembly referenciado.O
Usingelemento lista os namespaces que você deseja acessar. Este elemento é semelhante àusingdiretiva no Visual C#. ONamespaceatributo especifica o namespace a ser incluído.
Reference e Using os elementos são agnósticos em relação à linguagem. As tarefas embutidas podem ser escritas em qualquer uma das linguagens .NET CodeDom suportadas, por exemplo, Visual Basic ou Visual C#.
Observação
Os elementos contidos pelo Task elemento são específicos para a fábrica de tarefas, neste caso, a fábrica de tarefas de código.
Elemento de código
O último elemento filho a aparecer dentro do Task elemento é o Code elemento . O Code elemento contém ou localiza o código que você deseja que seja compilado em uma tarefa. O que você coloca no Code elemento depende de como você deseja escrever a tarefa.
O Language atributo especifica o idioma no qual o código é escrito. Os valores aceitáveis são cs para C#, vb para Visual Basic.
O Type atributo especifica o tipo de código encontrado no Code elemento .
Se o valor de
TypeéClass, então oCodeelemento contém código para uma classe que deriva da ITask interface.Se o valor de
TypeéMethod, então o código define uma substituição doExecutemétodo da ITask interface.Se o valor de
TypeéFragment, então o código define oExecuteconteúdo do método, mas não a assinatura ou areturninstrução.
O código em si normalmente aparece entre um <![CDATA[ marcador e um ]]> marcador. Como o código está em uma seção CDATA, você não precisa se preocupar em escapar de caracteres reservados, por exemplo, "<" ou ">".
Como alternativa, você pode usar o Source atributo do elemento para especificar o Code local de um arquivo que contém o código para sua tarefa. O código no arquivo de origem deve ser do tipo especificado pelo Type atributo. Se o Source atributo estiver presente, o valor padrão de Type é Class. Se Source não estiver presente, o valor padrão será Fragment.
Observação
Se você definir a classe de tarefa em um arquivo de origem, o nome da classe deverá concordar com o TaskName atributo do elemento UsingTask correspondente.
Hello World
Aqui está uma tarefa em linha mais robusta com RoslynCodeTaskFactoryo . A tarefa HelloWorld exibe "Olá, mundo!" no dispositivo de log de erros padrão, que normalmente é o console do sistema ou a janela de saída do Visual Studio. O Reference elemento no exemplo é incluído apenas para ilustração.
<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>
Você pode salvar a HelloWorld tarefa em um arquivo chamado HelloWorld.targets e, em seguida, invocá-la a partir de um projeto da seguinte maneira.
<Project>
<Import Project="HelloWorld.targets" />
<Target Name="Hello">
<HelloWorld />
</Target>
</Project>
Parâmetros de entrada e saída
Os parâmetros de tarefa embutidos são elementos filho de um ParameterGroup elemento. Cada parâmetro leva o nome do elemento que o define. O código a seguir define o parâmetro Text.
<ParameterGroup>
<Text />
</ParameterGroup>
Os parâmetros podem ter um ou mais destes atributos:
Requiredé um atributo opcional que éfalsepor padrão. Setrue, então o parâmetro é necessário e deve receber um valor antes de chamar a tarefa.ParameterTypeé um atributo opcional que éSystem.Stringpor padrão. Ele pode ser definido como qualquer tipo totalmente qualificado que seja um item ou um valor que possa ser convertido em e de uma cadeia de caracteres usando System.Convert.ChangeType. (Em outras palavras, qualquer tipo que possa ser passado de e para uma tarefa externa.)Outputé um atributo opcional que éfalsepor padrão. Setrue, então o parâmetro deve receber um valor antes de retornar do método Execute.
Por exemplo
<ParameterGroup>
<Expression Required="true" />
<Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<Tally ParameterType="System.Int32" Output="true" />
</ParameterGroup>
define estes três parâmetros:
Expressioné um parâmetro de entrada necessário do tipo System.String.Filesé um parâmetro de entrada de lista de itens obrigatório.Tallyé um parâmetro de saída do tipo System.Int32.
Se o Code elemento tiver o Type atributo de Fragment ou Method, as propriedades serão criadas automaticamente para cada parâmetro. Em RoslynCodeTaskFactory, se o Code elemento tiver o Type atributo de Class, então você não precisa especificar o ParameterGroup, uma vez que ele é inferido a partir do código-fonte (esta é uma diferença de CodeTaskFactory). Caso contrário, as propriedades devem ser explicitamente declaradas no código-fonte da tarefa e devem corresponder exatamente às suas definições de parâmetro.
Exemplo
A tarefa embutida a seguir registra algumas mensagens e retorna uma cadeia de caracteres.
<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>
Essas tarefas embutidas podem combinar caminhos e obter o nome do arquivo.
<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>
Fornecer compatibilidade com versões anteriores
RoslynCodeTaskFactory primeiro tornou-se disponível no MSBuild versão 15.8. Suponha que você queira oferecer suporte a versões anteriores do Visual Studio e MSBuild, quando RoslynCodeTaskFactory não estava disponível, mas CodeTaskFactory estava, mas deseja usar o mesmo script de compilação. Você pode usar uma Choose construção que usa a $(MSBuildVersion) propriedade para decidir em tempo de compilação se deve usar o RoslynCodeTaskFactory ou fallback para CodeTaskFactory, como no exemplo a seguir:
<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>