Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
RoslynCodeTaskFactory używa kompilatorów roslyn międzyplatformowych do generowania zestawów zadań w pamięci do użycia jako zadań wbudowanych.
RoslynCodeTaskFactory zadania docelowe platformy .NET Standard i mogą działać w środowiskach uruchomieniowych .NET Framework i .NET Core, a także na innych platformach, takich jak Linux i macOS.
Uwaga / Notatka
Element RoslynCodeTaskFactory jest dostępny tylko w programie MSBuild 15.8 lub nowszym. Wersje programu MSBuild są zgodne z wersjami programu Visual Studio, więc program RoslynCodeTaskFactory jest dostępny w programie Visual Studio 2017 w wersji 15.8 lub nowszej.
Struktura zadania wbudowanego z elementem RoslynCodeTaskFactory
RoslynCodeTaskFactory zadania wbudowane są deklarowane przy użyciu UsingTask elementu . Wbudowane zadanie i UsingTask element, który go zawiera, są zwykle uwzględniane w .targets pliku i importowane do innych plików projektu zgodnie z potrzebami. Oto podstawowe zadanie wbudowane. Zwróć uwagę, że nic nie robi.
<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>
Element UsingTask w przykładzie ma trzy atrybuty opisujące zadanie i wbudowaną fabrykę zadań, która ją kompiluje.
Atrybut
TaskNamenazywa zadanie , w tym przypadkuDoNothing.Atrybuty
TaskFactorynazwiją klasę, która implementuje fabrykę zadań wbudowanych.Atrybut
AssemblyFileudostępnia lokalizację wbudowanej fabryki zadań. Alternatywnie można użyć atrybutuAssemblyName, aby określić w pełni kwalifikowaną nazwę wbudowanej klasy fabryki zadań, która jest zwykle zlokalizowana w globalnej pamięci podręcznej zestawów (GAC).
Pozostałe elementy DoNothing zadania są puste i są udostępniane w celu zilustrowania kolejności i struktury zadania wbudowanego. Bardziej niezawodny przykład zostanie przedstawiony w dalszej części tego artykułu.
Element
ParameterGroupjest opcjonalny. Gdy zostanie określony, deklaruje parametry zadania. Aby uzyskać więcej informacji na temat parametrów wejściowych i wyjściowych, zobacz Parametry wejściowe i wyjściowe w dalszej części tego artykułu.Element
Taskopisuje i zawiera kod źródłowy zadania.Element
Referenceokreśla odwołania do zestawów .NET używanych w kodzie. Jest to odpowiednik dodawania odwołania do projektu w programie Visual Studio. AtrybutIncludeokreśla ścieżkę przywołytowanego zestawu.Element
Usingzawiera listę przestrzeni nazw, do których chcesz uzyskać dostęp. Ten element przypomina dyrektywęusingw języku Visual C#. AtrybutNamespaceokreśla przestrzeń nazw do uwzględnienia.
Reference i Using elementy są niezależne od języka. Zadania wbudowane można napisać w jednym z obsługiwanych języków .NET CodeDom, na przykład Visual Basic lub Visual C#.
Uwaga / Notatka
Elementy zawarte przez Task element są specyficzne dla fabryki zadań, w tym przypadku fabryki zadań kodu.
Code, element
Ostatnim elementem podrzędnym Task , który ma pojawić się w elemecie , jest Code element . Element Code zawiera lub lokalizuje kod, który chcesz skompilować w zadaniu. To, co umieścisz w elemenie Code , zależy od tego, jak chcesz napisać zadanie.
Atrybut Language określa język, w którym jest napisany kod. Dopuszczalne wartości to cs C#, vb dla języka Visual Basic.
Atrybut Type określa typ kodu, który znajduje się w elemecie Code .
Jeśli wartość
TypetoClass,Codeelement zawiera kod klasy pochodzącej z interfejsu ITask .Jeśli wartość
TypetoMethod, kod definiuje przesłonięćExecutemetodę interfejsu ITask .Jeśli wartość
TypetoFragment, kod definiuje zawartośćExecutemetody, ale nie podpis lub instrukcjęreturn.
Sam kod zwykle pojawia się między znacznikiem <![CDATA[ a znacznikiem ]]> . Ponieważ kod znajduje się w sekcji CDATA, nie musisz martwić się o ucieczkę zastrzeżonych znaków, na przykład "<" lub ">".
Alternatywnie możesz użyć Source atrybutu Code elementu, aby określić lokalizację pliku zawierającego kod zadania. Kod w pliku źródłowym musi być typu określony przez Type atrybut .
Source Jeśli atrybut jest obecny, wartość domyślna to TypeClass. Jeśli Source nie ma wartości, wartość domyślna to Fragment.
Uwaga / Notatka
Jeśli zdefiniujesz klasę zadań w pliku źródłowym, nazwa klasy musi być zgodna z atrybutem TaskName odpowiedniego elementu UsingTask .
Hello world
Oto bardziej niezawodne zadanie wbudowane z elementem RoslynCodeTaskFactory. Zadanie HelloWorld wyświetla komunikat "Hello, world!" na domyślnym urządzeniu rejestrowania błędów, które jest zazwyczaj konsolą systemową lub oknem danych wyjściowych programu Visual Studio. Element Reference w przykładzie jest dołączany tylko do ilustracji.
<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>
Zadanie można zapisać HelloWorld w pliku o nazwie HelloWorld.targets, a następnie wywołać je z projektu w następujący sposób.
<Project>
<Import Project="HelloWorld.targets" />
<Target Name="Hello">
<HelloWorld />
</Target>
</Project>
Parametry wejściowe i wyjściowe
Wbudowane parametry zadania to elementy podrzędne ParameterGroup elementu. Każdy parametr przyjmuje nazwę elementu, który go definiuje. Poniższy kod definiuje parametr Text.
<ParameterGroup>
<Text />
</ParameterGroup>
Parametry mogą mieć co najmniej jeden z następujących atrybutów:
Requiredjest opcjonalnym atrybutem, który jestfalsedomyślnie. Jeślitrueparametr jest wymagany i musi mieć wartość przed wywołaniem zadania.ParameterTypejest opcjonalnym atrybutem, który jestSystem.Stringdomyślnie. Można go ustawić na dowolny w pełni kwalifikowany typ, który jest elementem lub wartością, którą można przekonwertować na i z ciągu przy użyciu elementu System.Convert.ChangeType. (Innymi słowy, dowolny typ, który można przekazać do i z zadania zewnętrznego).Outputjest opcjonalnym atrybutem, który jestfalsedomyślnie. Jeślitrueparametr , należy podać wartość przed zwróceniem z metody Execute.
Na przykład
<ParameterGroup>
<Expression Required="true" />
<Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<Tally ParameterType="System.Int32" Output="true" />
</ParameterGroup>
definiuje następujące trzy parametry:
Expressionjest wymaganym parametrem wejściowym typu System.String.Filesjest wymaganym parametrem wejściowym listy elementów.Tallyjest parametrem wyjściowym typu System.Int32.
Code Jeśli element ma Type atrybut Fragment lub Method, właściwości są tworzone automatycznie dla każdego parametru. W pliku RoslynCodeTaskFactory, jeśli Code element ma Type atrybut Class, nie trzeba określać ParameterGroupelementu , ponieważ jest on wnioskowany z kodu źródłowego (jest to różnica od CodeTaskFactory). W przeciwnym razie właściwości muszą być jawnie zadeklarowane w kodzie źródłowym zadania i muszą dokładnie odpowiadać ich definicjom parametrów.
Przykład
Następujące wbudowane zadanie rejestruje niektóre komunikaty i zwraca ciąg.
<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>
Te wbudowane zadania mogą łączyć ścieżki i pobierać nazwę pliku.
<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>
Zapewnianie zgodności z poprzednimi wersjami
RoslynCodeTaskFactory po raz pierwszy stał się dostępny w programie MSBuild w wersji 15.8. Załóżmy, że chcesz obsługiwać poprzednie wersje programów Visual Studio i MSBuild, gdy RoslynCodeTaskFactory były niedostępne, ale CodeTaskFactory były, ale chcesz użyć tego samego skryptu kompilacji. Możesz użyć konstrukcji korzystającej Choose$(MSBuildVersion) z właściwości , aby zdecydować w czasie kompilacji, czy użyć RoslynCodeTaskFactory obiektu lub powrócić do CodeTaskFactoryelementu , jak w poniższym przykładzie:
<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>