Forrásgenerátorok
Ez a cikk áttekintést nyújt a .NET Fordítóplatform ("Roslyn") SDK részeként szállított forrásgenerátorokról. A forrásgenerátorok lehetővé teszik a C#-fejlesztők számára, hogy a fordítás során megvizsgálják a felhasználói kódot. A generátor menet közben létrehozhat új C#-forrásfájlokat, amelyeket hozzáad a felhasználó fordításához. Ily módon olyan kóddal rendelkezik, amely a fordítás során fut. Megvizsgálja a programot, hogy további forrásfájlokat állítson elő, amelyek a kód többi részével együtt vannak lefordítva.
A Forrásgenerátor egy új típusú összetevő, amelyet a C#-fejlesztők írhatnak, és két fő dolgot tehetnek:
Egy fordítási objektum lekérése , amely az összes lefordított felhasználói kódot jelöli. Ez az objektum megvizsgálható, és írhat olyan kódot, amely a lefordított kód szintaxisával és szemantikai modelljeivel működik, akárcsak a mai elemzők esetében.
Olyan C#-forrásfájlok létrehozása, amelyek összeállítás közben hozzáadhatók egy fordítási objektumhoz. Más szóval további forráskódot is megadhat egy fordítás bemeneteként a kód fordítása közben.
Ha kombináljuk, ez a két dolog teszi olyan hasznossá a Forrásgenerátorokat. A fordító által a fordítás során létrehozott összes gazdag metaadattal megvizsgálhatja a felhasználói kódot. A generátor ezután visszabocsátja a C#-kódot ugyanabba a fordításba, amely az ön által elemezett adatokon alapul. Ha ismeri a Roslyn-elemzőket, a Forrásgenerátorok olyan elemzőkként is felfoghatók, amelyek C#-forráskódot bocsáthatnak ki.
A forrásgenerátorok az alábbiakban vizualizált fordítási fázisként futnak:
A Forrásgenerátor egy .NET Standard 2.0-s szerelvény, amelyet a fordító tölt be minden elemzővel együtt. Olyan környezetekben használható, ahol a .NET Standard összetevők betölthetők és futtathatók.
Fontos
Jelenleg csak a .NET Standard 2.0 szerelvények használhatók forrásgenerátorként.
Gyakori forgatókönyvek
A felhasználói kód vizsgálatának és a technológiák által használt elemzésen alapuló információk vagy kódok előállításának három általános megközelítése van:
- Futásidejű tükröződés.
- MsBuild-feladatok zsonglőrítése.
- Köztes nyelv (IL) szövés (ez a cikk nem foglalkozik).
A forrásgenerátorok az egyes megközelítésekhez képest javulást jelenthetnek.
Futásidejű tükröződés
A futtatókörnyezeti tükröződés egy hatékony technológia, amelyet már régen hozzáadtak a .NET-hez. Számtalan forgatókönyv létezik a használatához. Gyakori forgatókönyv a felhasználói kód elemzésének végrehajtása, amikor egy alkalmazás elindul, és az adatok felhasználásával hoz létre dolgokat.
Például ASP.NET Core tükröződést használ, amikor a webszolgáltatás először futtatja az Ön által definiált szerkezeteket, hogy "bekenhesse" a vezérlőket és a borotvalapokat. Bár ez lehetővé teszi, hogy hatékony absztrakciókkal egyszerű kódot írjon, futásidőben teljesítménybírságot von maga után: amikor a webszolgáltatás vagy az alkalmazás először elindul, nem fogad el kéréseket, amíg az összes olyan futtatókörnyezeti tükröződési kód le nem fut, amely információkat derít fel a kódról. Bár ez a teljesítménybírság nem hatalmas, ez némileg rögzített költség, amelyet nem tud javítani saját alkalmazásában.
Forrásgenerátor esetén az indítás vezérlőfelderítési fázisa a fordítási időpontban történhet. A generátor elemezheti a forráskódot, és kibocsáthatja azt a kódot, amelyre szüksége van az alkalmazás "beírásához". A forrásgenerátorok használata gyorsabb indítási időket eredményezhet, mivel egy ma futó művelet leküldhető a fordítási időpontba.
MsBuild feladatok zsonglőrítése
A forrásgenerátorok olyan módokon javíthatják a teljesítményt, amelyek nem korlátozódnak a futásidőben történő tükröződésre a típusok felderítése érdekében. Egyes esetekben az MSBuild C#-feladat (CSC) többszöri meghívásával vizsgálhatják meg a fordításból származó adatokat. Képzelheti, hogy a fordító többszöri meghívása hatással van az alkalmazás létrehozásához szükséges teljes időre. Azt vizsgáljuk, hogy a Forrásgenerátorok hogyan használhatók az MSBuild-feladatok zsonglőrítésének szükségességének enyhítésére, mivel a forrásgenerátorok nem csupán néhány teljesítményelőnyt kínálnak, hanem lehetővé teszik az eszközök megfelelő absztrakciós szinten való működését is.
A forrásgenerátorok egy másik képességet is kínálhatnak, ha nem használják a "sztringgel begépelt" API-kat, például azt, hogy hogyan működik ASP.NET Core vezérlők és razor-lapok közötti útválasztás. Forrásgenerátor esetén az útválasztás erősen beírható úgy, hogy a szükséges sztringek fordítási idő részleteiként jönnek létre. Ez csökkenti, hogy egy helytelenül beírt sztringkonstans hányszor vezet olyan kéréshez, amely nem éri el a megfelelő vezérlőt.
A forrásgenerátorok használatának első lépései
Ebben az útmutatóban megismerkedhet egy forrásgenerátor API-val történő ISourceGenerator létrehozásával.
Hozzon létre egy .NET-konzolalkalmazást. Ez a példa a .NET 6-ot használja.
Cserélje le az osztályt
Program
a következő kódra. Az alábbi kód nem használ legfelső szintű utasításokat. A klasszikus űrlapra azért van szükség, mert ez az első forrásgenerátor részleges metódust ír ebben azProgram
osztályban:namespace ConsoleApp; partial class Program { static void Main(string[] args) { HelloFrom("Generated Code"); } static partial void HelloFrom(string name); }
Megjegyzés
A minta futtatható állapotban, de még semmi sem fog történni.
Ezután létrehozunk egy forrásgenerátorprojektet, amely implementálja a
partial void HelloFrom
metódus megfelelőjét.Hozzon létre egy standard .NET-kódtárprojektet, amely a
netstandard2.0
cél-keretrendszer monikerét (TFM) célozza meg. Adja hozzá a Microsoft.CodeAnalysis.Analyzers és a Microsoft.CodeAnalysis.CSharp NuGet-csomagokat:<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" PrivateAssets="all" /> <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" /> </ItemGroup> </Project>
Tipp
A forrásgenerátor projektnek meg kell céloznia a
netstandard2.0
TFM-et, különben nem fog működni.Hozzon létre egy új C#-fájlt HelloSourceGenerator.cs néven, amely a saját forrásgenerátorát a következőképpen határozza meg:
using Microsoft.CodeAnalysis; namespace SourceGenerator { [Generator] public class HelloSourceGenerator : ISourceGenerator { public void Execute(GeneratorExecutionContext context) { // Code generation goes here } public void Initialize(GeneratorInitializationContext context) { // No initialization required for this one } } }
A forrásgenerátornak egyaránt implementálnia kell az interfészt Microsoft.CodeAnalysis.ISourceGenerator , és rendelkeznie kell a következővel Microsoft.CodeAnalysis.GeneratorAttribute: . Nem minden forrásgenerátor igényel inicializálást, és ez a példa implementáció esetében is így van – ahol ISourceGenerator.Initialize üres.
Cserélje le a ISourceGenerator.Execute metódus tartalmát a következő implementációra:
using Microsoft.CodeAnalysis; namespace SourceGenerator { [Generator] public class HelloSourceGenerator : ISourceGenerator { public void Execute(GeneratorExecutionContext context) { // Find the main method var mainMethod = context.Compilation.GetEntryPoint(context.CancellationToken); // Build up the source code string source = $@"// <auto-generated/> using System; namespace {mainMethod.ContainingNamespace.ToDisplayString()} {{ public static partial class {mainMethod.ContainingType.Name} {{ static partial void HelloFrom(string name) => Console.WriteLine($""Generator says: Hi from '{{name}}'""); }} }} "; var typeName = mainMethod.ContainingType.Name; // Add the source code to the compilation context.AddSource($"{typeName}.g.cs", source); } public void Initialize(GeneratorInitializationContext context) { // No initialization required for this one } } }
context
Az objektumból hozzáférhetünk a fordítások belépési ponthoz vagyMain
metódushoz. AmainMethod
példány egy IMethodSymbol, és egy metódushoz vagy metódushoz hasonló szimbólumot jelöl (beleértve a konstruktort, a destruktort, az operátort vagy a tulajdonságot/esemény tartozékot). A Microsoft.CodeAnalysis.Compilation.GetEntryPoint metódus a IMethodSymbol program belépési pontjának értékét adja vissza. Más metódusok lehetővé teszik, hogy bármilyen metódusszimbólumot megtaláljon egy projektben. Ebből az objektumból meg tudjuk indokolni a tartalmazó névteret (ha van ilyen) és a típust. Ebbensource
a példában egy interpolált sztring található, amely a létrehozandó forráskódot sablonosíti, ahol az interpolált lyukak tele vannak a névteret tartalmazó és a típusadatokkal. Asource
hozzá van adva acontext
tipp nevéhez. Ebben a példában a generátor létrehoz egy új generált forrásfájlt, amely apartial
metódus implementációját tartalmazza a konzolalkalmazásban. A forrásgenerátorok írásához bármilyen forrást hozzáadhat.Tipp
A
hintName
metódus paramétere GeneratorExecutionContext.AddSource bármilyen egyedi név lehet. Gyakori, hogy explicit C#-fájlkiterjesztést ad meg, például".g.cs"
vagy".generated.cs"
a nevet. A fájlnév segít azonosítani a fájlt a létrehozott forrásként.Most már van egy működő generátorunk, de csatlakoztatnunk kell a konzolalkalmazáshoz. Szerkessze az eredeti konzolalkalmazás-projektet, és adja hozzá a következőt, és cserélje le a projekt elérési útját a fent létrehozott .NET Standard projektből származóra:
<!-- Add this as a new ItemGroup, replacing paths and names appropriately --> <ItemGroup> <ProjectReference Include="..\PathTo\SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> </ItemGroup>
Ez az új hivatkozás nem hagyományos projekthivatkozás, és manuálisan kell szerkeszteni a és
ReferenceOutputAssembly
azOutputItemType
attribútumok belefoglalásához. További információ aOutputItemType
ésReferenceOutputAssembly
attribútumokrólProjectReference
: Gyakori MSBuild projektelemek: ProjectReference.Most, amikor futtatja a konzolalkalmazást, látnia kell, hogy a létrehozott kód lefut, és a képernyőn jelenik meg. Maga a konzolalkalmazás nem implementálja a
HelloFrom
metódust, hanem a Forrásgenerátor projekt fordítása során létrehozott forrás. Az alábbi szöveg egy példakimenet az alkalmazásból:Generator says: Hi from 'Generated Code'
Megjegyzés
Előfordulhat, hogy újra kell indítania a Visual Studiót az IntelliSense megtekintéséhez és a hibák elhárításához, mivel az eszközhasználat aktívan javul.
Ha Visual Studiót használ, láthatja a forrás által létrehozott fájlokat. A Megoldáskezelő ablakban bontsa ki a Dependencies>Analyzers>SourceGenerator>SourceGenerator.HelloSourceGenerator elemet, és kattintson duplán a Program.g.cs fájlra.
A létrehozott fájl megnyitásakor a Visual Studio jelzi, hogy a fájl automatikusan létrejön, és nem szerkeszthető.
A buildtulajdonságok beállításával mentheti a létrehozott fájlt, és szabályozhatja a létrehozott fájlok tárolási helyét. A konzolalkalmazás projektfájljában adja hozzá az elemet egyhez
<EmitCompilerGeneratedFiles>
<PropertyGroup>
, és állítsa az értékét a értékretrue
. Hozza létre újra a projektet. A létrehozott fájlok most az obj/Debug/net6.0/generated/SourceGenerator/SourceGenerator.HelloSourceGenerator területen jönnek létre. Az elérési út összetevői a buildkonfigurációhoz, a cél-keretrendszerhez, a forrásgenerátor projekt nevéhez és a generátor teljes típusnevéhez felelnek meg. A kényelmesebb kimeneti mappát úgy választhatja ki, hogy hozzáadja az<CompilerGeneratedFilesOutputPath>
elemet az alkalmazás projektfájljába.
Következő lépések
A Source Generators Cookbook néhány ilyen példát mutat be, és néhány javasolt megközelítést alkalmaz a megoldásukhoz. Emellett rendelkezésre áll egy mintakészlet a GitHubon , amelyet önállóan is kipróbálhat.
A forrásgenerátorokról az alábbi cikkekben talál további információt:
Visszajelzés
https://aka.ms/ContentUserFeedback.
Hamarosan elérhető: 2024-ben fokozatosan kivezetjük a GitHub-problémákat a tartalom visszajelzési mechanizmusaként, és lecseréljük egy új visszajelzési rendszerre. További információ:Visszajelzés küldése és megtekintése a következőhöz: