Generator Sumber
Artikel ini memberikan ringkasan tentang Generator Sumber yang dikirimkan sebagai bagian dari .NET Compiler Platform ("Roslyn") SDK. Generator Sumber memungkinkan pengembang C# memeriksa kode pengguna saat sedang dikompilasi. Generator dapat membuat file sumber C# baru dengan cepat yang ditambahkan ke kompilasi pengguna. Dengan cara ini, Anda memiliki kode yang terus berjalan selama kompilasi. Hal ini memeriksa program Anda untuk menghasilkan file sumber tambahan yang dikompilasi bersamaan dengan sisa kode Anda.
Generator Sumber adalah jenis komponen baru yang dapat ditulis oleh pengembang C# yang memungkinkan Anda melakukan dua hal utama:
Ambil objek kompilasi yang mewakili semua kode pengguna yang sedang dikompilasi. Objek ini dapat diperiksa, dan Anda dapat menulis kode yang berfungsi dengan sintaks dan model semantik untuk kode yang sedang dikompilasi, seperti halnya dengan analis saat ini.
Hasilkan file sumber C# yang dapat ditambahkan ke objek kompilasi selama proses kompilasi. Dengan kata lain, Anda dapat memberikan kode sumber tambahan sebagai input ke kompilasi saat kode sedang dikompilasi.
Jika digabungkan, kedua hal inilah yang membuat Generator Sumber sangat berguna. Anda dapat memeriksa kode pengguna dengan semua metadata kaya yang dibuat oleh kompilator selama kompilasi. Generator Anda kemudian menunjukkan kode C# kembali ke kompilasi yang sama yang didasarkan pada data yang telah Anda analisis. Jika Anda terbiasa dengan Roslyn Analyzers, Anda dapat menganggap Generator Sumber sebagai analis yang dapat menunjukkan kode sumber C#.
Generator sumber berjalan sebagai fase kompilasi yang divisualisasikan di bawah ini:
Generator Sumber adalah rakitan .NET Standar 2.0 yang dimuat oleh kompilator bersamaan dengan analis. Ini dapat digunakan di lingkungan tempat komponen .NET Standar dapat dimuat dan dijalankan.
Penting
Saat ini hanya rakitan .NET Standar 2.0 yang dapat digunakan sebagai Generator Sumber.
Skenario umum
Ada tiga pendekatan umum untuk memeriksa kode pengguna dan menghasilkan informasi atau kode berdasarkan analisis yang digunakan oleh teknologi saat ini:
- Refleksi runtime.
- Menjalankan tugas MSBuild.
- Pembentukan Bahasa Perantara (IL) (tidak dibahas dalam artikel ini).
Generator Sumber dapat menjadi sebuah peningkatan atas setiap pendekatan.
Refleksi durasi
Refleksi durasi adalah teknologi canggih yang ditambahkan ke .NET sejak lama. Ada banyak skenario untuk menggunakannya. Skenario umum adalah melakukan beberapa analisis kode pengguna saat aplikasi dimulai dan menggunakan data tersebut untuk menghasilkan sesuatu.
Misalnya, ASP.NET Core menggunakan refleksi saat layanan web Anda pertama kali berjalan untuk menemukan konstruksi yang telah Anda tetapkan sehingga dapat "menyambungkan" hal-hal seperti pengontrol dan halaman razor. Meskipun ini memungkinkan Anda untuk menulis kode langsung dengan abstraksi yang kuat, hal tersebut datang dengan penalti kinerja pada waktu berjalan: ketika layanan web atau aplikasi Anda pertama kali dijalankan, itu tidak dapat menerima permintaan apa pun sampai semua kode refleksi runtime yang menunjukkan informasi bahwa kode Anda selesai dijalankan. Meskipun penalti kinerja ini tidak besar, ini adalah biaya tetap yang tidak dapat Anda tingkatkan sendiri di aplikasi Anda sendiri.
Dengan Generator Sumber, fase penemuan pengontrol startup dapat terjadi pada saat kompilasi. Generator dapat menganalisis kode sumber Anda dan menunjukkan kode yang diperlukan untuk "menyambungkan" aplikasi Anda. Menggunakan generator sumber membuat waktu startup lebih cepat, karena tindakan yang terjadi pada waktu proses hari ini dapat didorong ke waktu kompilasi.
Menjalankan tugas MSBuild
Generator Sumber dapat meningkatkan performa dengan cara yang tidak hanya dibatasi pada refleksi durasi yang juga untuk menemukan jenis. Beberapa skenario melibatkan panggilan tugas MSBuild C# (disebut CSC) beberapa kali sehingga mereka dapat memeriksa data dari kompilasi. Seperti yang mungkin Anda bayangkan, memanggil kompilator lebih dari sekali memengaruhi total waktu yang dibutuhkan untuk membangun aplikasi Anda. Kami sedang menyelidiki bagaimana Generator Sumber dapat digunakan untuk menghilangkan kebutuhan untuk menjalankan tugas MSBuild seperti ini, karena generator Sumber tidak hanya menawarkan beberapa manfaat performa, tetapi juga memungkinkan alat untuk beroperasi pada tingkat abstraksi yang tepat.
Kemampuan lain yang dapat ditawarkan Generator Sumber adalah mewajibkan penggunaan beberapa API "diketik dengan string", seperti cara kerja perutean ASP.NET Core antara pengontrol dan halaman razor. Dengan Generator Sumber, perutean dapat diketik dengan kuat dengan string penting yang dihasilkan sebagai detail waktu kompilasi. Ini akan mengurangi berapa kali string yang salah ketik secara harfiah mengarah ke permintaan yang tidak mencapai pengontrol yang tepat.
Memulai dengan generator sumber
Dalam panduan ini, Anda akan menjelajahi pembuatan generator sumber menggunakan ISourceGenerator API.
Buat aplikasi konsol .NET baru. Contoh ini menggunakan .NET 6.
Ganti kelas
Program
Anda dengan kode berikut. Kode berikut tidak menggunakan pernyataan tingkat atas. Formulir klasik diperlukan karena generator sumber pertama ini menulis metode parsial di kelas tersebutProgram
:namespace ConsoleApp; partial class Program { static void Main(string[] args) { HelloFrom("Generated Code"); } static partial void HelloFrom(string name); }
Catatan
Anda dapat menjalankan sampel ini apa adanya, tetapi tidak akan terjadi apa-apa.
Selanjutnya, kita akan membuat proyek generator sumber yang akan mengimplementasikan padanan metode
partial void HelloFrom
.Buat proyek pustaka standar .NET yang menargetkan bingkai target moniker (TFM)
netstandard2.0
. Tambahkan paket NuGet Microsoft.CodeAnalysis.Analyzers dan Microsoft.CodeAnalysis.CSharp:<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>
Tip
Proyek generator sumber perlu menargetkan TFM
netstandard2.0
, jika tidak, maka tidak akan berfungsi.Buat file C# baru bernama HelloSourceGenerator.cs yang menentukan Generator Sumber Anda sendiri seperti:
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 } } }
Generator sumber perlu mengimplementasikan antarmuka Microsoft.CodeAnalysis.ISourceGenerator, dan memiliki Microsoft.CodeAnalysis.GeneratorAttribute. Tidak semua generator sumber memerlukan inisialisasi, dan itulah yang terjadi dengan contoh implementasi ini—di mana ISourceGenerator.Initialize kosong.
Ganti konten metode ISourceGenerator.Execute dengan implementasi berikut:
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 } } }
Dari objek
context
kita dapat mengakses titik masuk kompilasi, atau metodeMain
. InstansmainMethod
adalah IMethodSymbol, dan mewakili metode atau simbol seperti metode (termasuk konstruktor, destruktor, operator, atau pengakses properti/kejadian). Metode Microsoft.CodeAnalysis.Compilation.GetEntryPoint mengembalikan IMethodSymbol untuk titik masuk program. Metode lain memungkinkan Anda untuk menemukan simbol metode apa pun dalam sebuah proyek. Dari objek ini, kita dapat menjelaskan tentang namespace layanan yang berisi (jika ada) dan jenisnya.source
dalam contoh ini adalah string yang diinterpolasi yang membuat template kode sumber yang akan dihasilkan, di mana lubang yang diinterpolasi diisi dengan namespace layanan yang berisi dan informasi jenis.source
ditambahkan kecontext
dengan nama petunjuk. Untuk contoh ini, generator membuat file sumber baru yang berisi implementasi metodepartial
dalam aplikasi konsol. Anda dapat menulis generator sumber untuk menambahkan sumber apa pun yang Anda inginkan.Tip
Parameter
hintName
dari metode GeneratorExecutionContext.AddSource dapat berupa nama unik apa pun. Sangat umum untuk menyediakan ekstensi file C# eksplisit seperti".g.cs"
atau".generated.cs"
untuk namanya. Nama file membantu mengidentifikasi file sebagai sumber yang dihasilkan.Sekarang kita memiliki generator yang telah berfungsi, tetapi perlu menghubungkannya ke aplikasi konsol kita. Edit proyek aplikasi konsol asli dan tambahkan berikut ini, ganti jalur proyek dengan yang dari proyek .NET Standar yang Anda buat di atas:
<!-- Add this as a new ItemGroup, replacing paths and names appropriately --> <ItemGroup> <ProjectReference Include="..\PathTo\SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> </ItemGroup>
Referensi baru ini bukan referensi proyek tradisional, dan harus diedit secara manual untuk menyertakan atribut
OutputItemType
danReferenceOutputAssembly
. Untuk informasi selengkapnya tentang atributOutputItemType
danReferenceOutputAssembly
ProjectReference
, lihat Item proyek MSBuild umum: ProjectReference.Sekarang, ketika Anda menjalankan aplikasi konsol, Anda akan melihat bahwa kode yang dihasilkan telah dijalankan dan dicetak ke layar. Aplikasi konsol itu sendiri tidak mengimplementasikan metode
HelloFrom
, melainkan sumber yang dihasilkan selama kompilasi dari proyek Generator Sumber. Teks berikut adalah contoh output dari jendela konsol klien:Generator says: Hi from 'Generated Code'
Catatan
Anda mungkin perlu hidupkan ulang Visual Studio untuk melihat IntelliSense dan menghapus kesalahan karena pengalaman peralatan secara aktif ditingkatkan.
Jika Anda menggunakan Visual Studio, Anda dapat melihat file yang dihasilkan sumber. Dari jendela Penjelajah Solusi, perluas Dependencies>Analyzers>SourceGenerator>SourceGenerator.HelloSourceGenerator , dan klik dua kali file Program.g.cs.
Ketika Anda membuka file yang dihasilkan ini, Visual Studio akan menunjukkan bahwa file dibuat secara otomatis dan tidak dapat diedit.
Anda juga dapat mengatur properti build untuk menyimpan file yang dihasilkan dan mengontrol tempat penyimpanan file yang dihasilkan. Di file proyek aplikasi konsol, tambahkan elemen
<EmitCompilerGeneratedFiles>
ke<PropertyGroup>
, dan atur nilainya ketrue
. Bangun kembali proyek Anda. Sekarang, file yang dihasilkan dibuat di bawah obj/Debug/net6.0/generated/SourceGenerator/SourceGenerator.HelloSourceGenerator. Komponen peta jalur ke konfigurasi build, bingkai target, nama proyek generator sumber, dan nama jenis generator yang sepenuhnya memenuhi syarat. Anda dapat memilih folder output yang lebih nyaman dengan menambahkan elemen<CompilerGeneratedFilesOutputPath>
ke file proyek aplikasi.
Langkah berikutnya
Cookbook Generator Sumber membahas beberapa contoh berikut dengan beberapa pendekatan yang disarankan untuk menyelesaikannya. Selain itu, kami memiliki sekumpulan sampel yang tersedia di GitHub yang dapat Anda coba sendiri.
Anda dapat mempelajari lebih lanjut tentang Generator Sumber di artikel ini: