Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
RoslynCodeTaskFactory verwendet die plattformübergreifenden Roslyn-Compiler, um Speicheraufgabenassemblys für die Verwendung als Inlineaufgaben zu generieren.
RoslynCodeTaskFactory Aufgaben zielen auf .NET Standard ab und können auf .NET Framework- und .NET Core-Runtimes sowie auf anderen Plattformen wie Linux und macOS arbeiten.
Hinweis
Die RoslynCodeTaskFactory ist nur in MSBuild 15.8 und höher verfügbar. MSBuild-Versionen folgen Visual Studio-Versionen, sodass RoslynCodeTaskFactory in Visual Studio 2017, Version 15.8 und höher, verfügbar ist.
Die Struktur einer Inlineaufgabe mit RoslynCodeTaskFactory
RoslynCodeTaskFactory Inlineaufgaben werden mithilfe des UsingTask Elements deklariert. Die Inlineaufgabe und das UsingTask darin enthaltene Element sind in der Regel in einer .targets Datei enthalten und bei Bedarf in andere Projektdateien importiert. Hier ist eine einfache Inlineaufgabe. Beachten Sie, dass sie nichts tut.
<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>
Das UsingTask Element im Beispiel verfügt über drei Attribute, die die Aufgabe und die Inlineaufgabenfactory beschreiben, die sie kompiliert.
Das
TaskNameAttribut benennt die Aufgabe in diesem FallDoNothing.Das
TaskFactoryAttribut benennt die Klasse, die die Inlineaufgabenfactory implementiert.Das
AssemblyFileAttribut gibt die Position der Inlineaufgabenfactory an. Alternativ können Sie dasAssemblyNameAttribut verwenden, um den vollqualifizierten Namen der Inlineaufgaben-Factoryklasse anzugeben, die sich normalerweise im globalen Assemblycache (GAC) befindet.
Die verbleibenden Elemente des DoNothing Vorgangs sind leer und werden bereitgestellt, um die Reihenfolge und Struktur eines Inlinevorgangs zu veranschaulichen. Ein robusteres Beispiel wird weiter unten in diesem Artikel vorgestellt.
Das
ParameterGroup-Element ist optional. Wenn angegeben, deklariert sie die Parameter für den Vorgang. Weitere Informationen zu Eingabe- und Ausgabeparametern finden Sie weiter unten in diesem Artikel unter "Eingabe- und Ausgabeparameter ".Das
TaskElement beschreibt und enthält den Quellcode der Aufgabe.Das
ReferenceElement gibt Verweise auf die .NET-Assemblys an, die Sie in Ihrem Code verwenden. Dies entspricht dem Hinzufügen eines Verweises auf ein Projekt in Visual Studio. DasIncludeAttribut gibt den Pfad der Assembly an, auf die verwiesen wird.Das
UsingElement listet die Namespaces auf, auf die Sie zugreifen möchten. Dieses Element ähnelt derusingDirektive in Visual C#. DasNamespaceAttribut gibt den einzuschließden Namespace an.
Reference und Using Elemente sind sprachunabhängig. Inlineaufgaben können in einer der unterstützten .NET CodeDom-Sprachen geschrieben werden, z. B. Visual Basic oder Visual C#.
Hinweis
Elemente, die Task vom Element enthalten sind, sind spezifisch für die Aufgabenfactory, in diesem Fall die Codeaufgabenfactory.
Codeelement
Das letzte untergeordnete Element, das innerhalb des Task Elements angezeigt werden soll, ist das Code Element. Das Code Element enthält oder sucht den Code, den Sie in einer Aufgabe kompilieren möchten. Was Sie in das Code Element einfügen, hängt davon ab, wie Sie die Aufgabe schreiben möchten.
Das Language Attribut gibt die Sprache an, in der Ihr Code geschrieben wird. Zulässige Werte sind cs für C# vb für Visual Basic.
Das Type Attribut gibt den Codetyp an, der Code im Element gefunden wird.
Wenn der Wert lautet
TypeClass, enthält dasCodeElement Code für eine Klasse, die von der ITask Schnittstelle abgeleitet wird.Wenn der Wert
TypelautetMethod, definiert der Code eine Außerkraftsetzung derExecuteMethode der ITask Schnittstelle.Wenn der Wert von
TypeistFragment, definiert der Code den Inhalt derExecuteMethode, aber nicht die Signatur oder diereturnAnweisung.
Der Code selbst wird in der Regel zwischen einer <![CDATA[ Markierung und einer ]]> Markierung angezeigt. Da sich der Code in einem CDATA-Abschnitt befindet, müssen Sie sich keine Gedanken darüber machen, reservierte Zeichen zu entfernen, z. B. "<" oder ">".
Alternativ können Sie das Source Attribut des Code Elements verwenden, um den Speicherort einer Datei anzugeben, die den Code für ihre Aufgabe enthält. Der Code in der Quelldatei muss vom Typ sein, der durch das Type Attribut angegeben wird. Wenn das Source Attribut vorhanden ist, lautet Classder Standardwert von Type . Wenn Source nicht vorhanden, lautet Fragmentder Standardwert .
Hinweis
Wenn Sie die Aufgabenklasse in einer Quelldatei definieren, muss der Klassenname dem TaskName Attribut des entsprechenden UsingTask-Elements zustimmen.
Hallo Welt
Hier ist eine robustere Inlineaufgabe mit RoslynCodeTaskFactory. Die HelloWorld-Aufgabe zeigt "Hello, world!" auf dem Standardmäßigen Fehlerprotokollierungsgerät an, das in der Regel die Systemkonsole oder das Visual Studio-Ausgabefenster ist. Das Reference Element im Beispiel ist nur zur Veranschaulichung enthalten.
<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>
Sie können den HelloWorld Vorgang in einer Datei mit dem Namen "HelloWorld.targets" speichern und dann wie folgt aus einem Projekt aufrufen.
<Project>
<Import Project="HelloWorld.targets" />
<Target Name="Hello">
<HelloWorld />
</Target>
</Project>
Eingabe- und Ausgabeparameter
Inlineaufgabenparameter sind untergeordnete Elemente eines ParameterGroup Elements. Jeder Parameter verwendet den Namen des Elements, das es definiert. Der folgende Code definiert den Parameter Text.
<ParameterGroup>
<Text />
</ParameterGroup>
Parameter können mindestens eins dieser Attribute aufweisen:
Requiredist ein optionales Attribut, das standardmäßig istfalse. Wenntrue, dann ist der Parameter erforderlich und muss vor dem Aufrufen der Aufgabe einen Wert erhalten.ParameterTypeist ein optionales Attribut, das standardmäßig istSystem.String. Er kann auf einen vollqualifizierten Typ festgelegt werden, der entweder ein Element oder ein Wert ist, der mithilfe von System.Convert.ChangeType in eine und aus einer Zeichenfolge konvertiert werden kann. (Mit anderen Worten, jeder Typ, der an und von einem externen Vorgang übergeben werden kann.)Outputist ein optionales Attribut, das standardmäßig istfalse. Iftrue, then the parameter must be given a value before returning from the Execute method.
Beispiel:
<ParameterGroup>
<Expression Required="true" />
<Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<Tally ParameterType="System.Int32" Output="true" />
</ParameterGroup>
definiert die folgenden drei Parameter:
Expressionist ein erforderlicher Eingabeparameter vom Typ "System.String".Filesist ein erforderlicher Eingabeparameter für Elementlisten.Tallyist ein Ausgabeparameter vom Typ "System.Int32".
Wenn das Code Element über das Type Attribut oder Methoddas Attribut verfügtFragment, werden eigenschaften automatisch für jeden Parameter erstellt. Wenn das Element das CodeType Attribut hat, müssen Sie in RoslynCodeTaskFactory das Attribut nicht Classangeben ParameterGroup, da es aus dem Quellcode abgeleitet wird (dies ist ein Unterschied von CodeTaskFactory). Andernfalls müssen Eigenschaften explizit im Aufgabenquellcode deklariert werden und müssen exakt mit ihren Parameterdefinitionen übereinstimmen.
Beispiel
Die folgende Inlineaufgabe protokolliert einige Nachrichten und gibt eine Zeichenfolge zurück.
<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>
Diese Inlineaufgaben können Pfade kombinieren und den Dateinamen abrufen.
<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>
Bereitstellen der Abwärtskompatibilität
RoslynCodeTaskFactory wurde zuerst in MSBuild, Version 15.8, verfügbar. Angenommen, Sie möchten frühere Versionen von Visual Studio und MSBuild unterstützen, wenn RoslynCodeTaskFactory sie nicht verfügbar war, aber CodeTaskFactory sie möchten dasselbe Buildskript verwenden. Sie können ein Choose Konstrukt verwenden, das die $(MSBuildVersion) Eigenschaft verwendet, um zur Erstellungszeit zu entscheiden, ob sie die RoslynCodeTaskFactory oder den Fallback verwenden CodeTaskFactorysoll, wie im folgenden Beispiel gezeigt:
<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>