Bagikan melalui


Penganalisis Roslyn dan pustaka sadar kode untuk ImmutableArrays

.NET Compiler Platform ("Roslyn") membantu Anda membangun pustaka yang sadar kode. Pustaka sadar kode menyediakan fungsionalitas yang dapat Anda gunakan dan alat (penganalisis Roslyn) untuk membantu Anda menggunakan pustaka dengan cara terbaik atau untuk menghindari kesalahan. Topik ini menunjukkan kepada Anda cara membangun penganalisis Roslyn dunia nyata untuk menangkap kesalahan umum saat menggunakan paket NuGet System.Collections.Immutable . Contoh ini juga menunjukkan cara memberikan perbaikan kode untuk masalah kode yang ditemukan oleh penganalisis. Pengguna melihat perbaikan kode di UI bola lampu Visual Studio dan dapat menerapkan perbaikan untuk kode secara otomatis.

Mulai

Anda memerlukan hal berikut untuk membuat contoh ini:

  • Visual Studio 2015 (bukan Edisi Ekspres) atau versi yang lebih baru. Anda dapat menggunakan Visual Studio Community Edition gratis
  • Visual Studio SDK. Anda juga dapat, saat menginstal Visual Studio, periksa Alat Ekstensibilitas Visual Studio di bawah Alat Umum untuk menginstal SDK secara bersamaan. Jika Anda telah menginstal Visual Studio, Anda juga dapat menginstal SDK ini dengan masuk ke menu utama File>Proyek Baru>, memilih C# di panel navigasi kiri, lalu memilih Ekstensibilitas. Saat Anda memilih templat proyek breadcrumb "Instal Alat Ekstensibilitas Visual Studio", templat proyek breadcrumb meminta Anda untuk mengunduh dan menginstal SDK.
  • .NET Compiler Platform ("Roslyn") SDK. Anda juga dapat menginstal SDK ini dengan masuk ke menu utama File>Proyek Baru>, memilih C# di panel navigasi kiri, lalu memilih Ekstensibilitas. Ketika Anda memilih templat proyek breadcrumb "Unduh .NET Compiler Platform SDK", itu meminta Anda untuk mengunduh dan menginstal SDK. SDK ini mencakup Roslyn Sintaks Visualizer. Alat yang berguna ini membantu Anda mencari tahu jenis model kode apa yang harus Anda cari di penganalisis Anda. Infrastruktur penganalisis memanggil kode Anda untuk jenis model kode tertentu, sehingga kode Anda hanya dijalankan jika perlu dan hanya dapat berfokus pada analisis kode yang relevan.

Apa masalahnya?

Bayangkan Anda menyediakan pustaka dengan dukungan ImmutableArray (misalnya, System.Collections.Immutable.ImmutableArray<T>). Pengembang C# memiliki banyak pengalaman dengan array .NET. Namun, karena sifat ImmutableArrays dan teknik pengoptimalan yang digunakan dalam implementasi, intuisi pengembang C# menyebabkan pengguna pustaka Anda menulis kode rusak, seperti yang dijelaskan di bawah ini. Selain itu, pengguna tidak melihat kesalahan mereka sampai run time, yang bukan pengalaman kualitas yang biasa mereka gunakan di Visual Studio dengan .NET.

Pengguna terbiasa menulis kode seperti berikut:

var a1 = new int[0];
Console.WriteLine("a1.Length = { 0}", a1.Length);
var a2 = new int[] { 1, 2, 3, 4, 5 };
Console.WriteLine("a2.Length = { 0}", a2.Length);

Membuat array kosong untuk diisi dengan baris kode berikutnya dan menggunakan sintaks penginisialisasi koleksi sudah tidak asing lagi oleh pengembang C#. Namun, menulis kode yang sama untuk ImmutableArray mengalami crash pada waktu proses:

var b1 = new ImmutableArray<int>();
Console.WriteLine("b1.Length = { 0}", b1.Length);
var b2 = new ImmutableArray<int> { 1, 2, 3, 4, 5 };
Console.WriteLine("b2.Length = { 0}", b2.Length);

Kesalahan pertama adalah karena implementasi ImmutableArray menggunakan struct untuk membungkus penyimpanan data yang mendasar. Struct harus memiliki konstruktor tanpa parameter sehingga default(T) ekspresi dapat mengembalikan struct dengan semua anggota nol atau null. Ketika kode mengakses b1.Length, ada kesalahan dereferensi null run time karena tidak ada array penyimpanan yang mendasari dalam struktur ImmutableArray. Cara yang benar untuk membuat ImmutableArray kosong adalah ImmutableArray<int>.Empty.

Kesalahan dengan penginisialisasi koleksi terjadi karena ImmutableArray.Add metode mengembalikan instans baru setiap kali Anda memanggilnya. Karena ImmutableArrays tidak pernah berubah, ketika Anda menambahkan elemen baru, Anda mendapatkan kembali objek ImmutableArray baru (yang dapat berbagi penyimpanan karena alasan performa dengan ImmutableArray yang sudah ada sebelumnya). Karena b2 menunjuk ke ImmutableArray pertama sebelum memanggil Add() lima kali, b2 adalah ImmutableArray default. Panjang Panggilan di atasnya juga mengalami crash dengan kesalahan dereferensi null. Cara yang benar untuk menginisialisasi ImmutableArray tanpa memanggil Tambahkan secara manual adalah dengan menggunakan ImmutableArray.CreateRange(new int[] {1, 2, 3, 4, 5}).

Menemukan jenis simpul sintaks yang relevan untuk memicu penganalisis Anda

Untuk mulai membangun penganalisis, pertama-tama cari tahu jenis SintaksNode apa yang perlu Anda cari. Luncurkan Sintaks Visualizer dari menu Lihat>Visualizer Sintaks Windows>Roslyn Lainnya.

Tempatkan tanda sisipan editor pada baris yang menyatakan b1. Anda akan melihat Sintaks Visualizer menunjukkan bahwa Anda berada dalam simpul LocalDeclarationStatement pohon sintaksis. Simpul ini memiliki VariableDeclaration, yang pada gilirannya memiliki VariableDeclarator, yang pada gilirannya memiliki EqualsValueClause, dan akhirnya ada ObjectCreationExpression. Saat Anda mengeklik pohon Sintaks Visualizer simpul, sintaks di jendela editor disorot untuk menunjukkan kode yang diwakili oleh simpul tersebut. Nama subtitik SintaksNode cocok dengan nama yang digunakan dalam tata bahasa C#.

Membuat proyek penganalisis

Dari menu utama, pilih File>Proyek Baru.> Dalam dialog Proyek Baru, di bawah proyek C# di bilah navigasi kiri, pilih Ekstensibilitas, dan di panel kanan pilih templat proyek Analyzer with Code Fix. Masukkan nama dan konfirmasi dialog.

Templat membuka file DiagnosticAnalyzer.cs . Pilih tab buffer editor tersebut. File ini memiliki kelas penganalisis (dibentuk dari nama yang Anda berikan proyek) yang berasal dari DiagnosticAnalyzer (jenis API Roslyn). Kelas baru Anda memiliki DiagnosticAnalyzerAttribute pendeklarasikan bahwa penganalisis Anda relevan dengan bahasa C# sehingga pengkompilasi menemukan dan memuat penganalisis Anda.

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class ImmutableArrayAnalyzerAnalyzer : DiagnosticAnalyzer
{}

Anda dapat menerapkan penganalisis menggunakan Visual Basic yang menargetkan kode C#, dan sebaliknya. Lebih penting dalam DiagnosticAnalyzerAttribute untuk memilih apakah penganalisis Anda menargetkan satu bahasa atau keduanya. Penganalisis yang lebih canggih yang memerlukan pemodelan terperinci bahasa hanya dapat menargetkan satu bahasa. Jika penganalisis Anda, misalnya, hanya memeriksa nama jenis atau nama anggota publik, mungkin untuk menggunakan model bahasa umum yang ditawarkan Roslyn di seluruh Visual Basic dan C#. Misalnya, FxCop memperingatkan bahwa kelas mengimplementasikan ISerializable, tetapi kelas tidak memiliki SerializableAttribute atribut independen bahasa dan berfungsi untuk kode Visual Basic dan C#.

Menginisialisasi penganalisis

Gulir ke bawah sedikit di DiagnosticAnalyzer kelas untuk melihat Initialize metode . Pengkompilasi memanggil metode ini saat mengaktifkan penganalisis. Metode ini mengambil AnalysisContext objek yang memungkinkan penganalisis Anda mendapatkan informasi konteks dan mendaftarkan panggilan balik untuk peristiwa untuk jenis kode yang ingin Anda analisis.

public override void Initialize(AnalysisContext context) {}

Buka baris baru dalam metode ini dan ketik "konteks." untuk melihat daftar penyelesaian IntelliSense. Anda dapat melihat dalam daftar penyelesaian ada banyak Register... metode untuk menangani berbagai jenis peristiwa. Misalnya, yang pertama, RegisterCodeBlockAction, memanggil kembali ke kode Anda untuk blok, yang biasanya merupakan kode antara kurung kurawal. Mendaftar untuk blok juga memanggil kembali ke kode Anda untuk inisialisasi bidang, nilai yang diberikan ke atribut, atau nilai parameter opsional.

Sebagai contoh lain, RegisterCompilationStartAction, memanggil kembali ke kode Anda di awal kompilasi, yang berguna ketika Anda perlu mengumpulkan status di banyak lokasi. Anda dapat membuat struktur data, misalnya, untuk mengumpulkan semua simbol yang digunakan, dan setiap kali penganalisis Anda dipanggil kembali untuk beberapa sintaks atau simbol, Anda dapat menyimpan informasi tentang setiap lokasi dalam struktur data Anda. Ketika Anda dipanggil kembali karena kompilasi berakhir, Anda dapat menganalisis semua lokasi yang Anda simpan, misalnya, untuk melaporkan simbol apa yang digunakan kode dari setiap using pernyataan.

Dengan menggunakan Sintaks Visualizer, Anda mempelajari bahwa Anda ingin dipanggil saat pengompilasi memproses ObjectCreationExpression. Anda menggunakan kode ini untuk menyiapkan panggilan balik:

context.RegisterSyntaxNodeAction(c => AnalyzeObjectCreation(c),
                                 SyntaxKind.ObjectCreationExpression);

Anda mendaftar untuk simpul sintaksis dan memfilter hanya untuk simpul sintaks pembuatan objek. Menurut konvensi, penulis penganalisis menggunakan lambda saat mendaftarkan tindakan, yang membantu menjaga penganalisis tetap stateless. Anda dapat menggunakan fitur Visual Studio Hasilkan Dari Penggunaan untuk membuat AnalyzeObjectCreation metode . Ini menghasilkan jenis parameter konteks yang benar untuk Anda juga.

Mengatur properti untuk pengguna penganalisis Anda

Sehingga penganalisis Anda muncul di UI Visual Studio dengan tepat, cari dan ubah baris kode berikut untuk mengidentifikasi penganalisis Anda:

internal const string Category = "Naming";

Ubah "Naming" ke "API Guidance".

Selanjutnya temukan dan buka file Resources.resx di proyek Anda menggunakan Penjelajah Solusi. Anda dapat memasukkan deskripsi untuk penganalisis, judul, dll. Anda dapat mengubah nilai untuk semua ini menjadi "Don't use ImmutableArray<T> constructor" untuk saat ini. Anda dapat menempatkan argumen pemformatan string dalam string Anda ({0}, , {1}dll.), dan kemudian ketika Anda memanggil Diagnostic.Create(), Anda dapat menyediakan params array argumen yang akan diteruskan.

Menganalisis ekspresi pembuatan objek

Metode ini AnalyzeObjectCreation mengambil jenis konteks yang berbeda yang disediakan oleh kerangka kerja penganalisis kode. Metode Initialize ini AnalysisContext memungkinkan Anda mendaftarkan panggilan balik tindakan untuk menyiapkan penganalisis Anda. SyntaxNodeAnalysisContext, misalnya, memiliki CancellationToken yang dapat Anda lewati. Jika pengguna mulai mengetik di editor, Roslyn akan membatalkan penganalisis yang sedang berjalan untuk menyimpan pekerjaan dan meningkatkan performa. Sebagai contoh lain, konteks ini memiliki properti Node yang mengembalikan simpul sintaks pembuatan objek.

Dapatkan simpul, yang dapat Anda asumsikan adalah jenis yang Anda filter tindakan simpul sintaks:

var objectCreation = (ObjectCreationExpressionSyntax)context.Node;

Luncurkan Visual Studio dengan penganalisis Anda untuk pertama kalinya

Luncurkan Visual Studio dengan membangun dan menjalankan penganalisis Anda (tekan F5). Karena proyek startup di Penjelajah Solusi adalah proyek VSIX, menjalankan kode Anda membangun kode dan VSIX, lalu meluncurkan Visual Studio dengan VSIX yang diinstal. Saat Anda meluncurkan Visual Studio dengan cara ini, Visual Studio diluncurkan dengan sarang registri yang berbeda sehingga penggunaan utama Visual Studio Anda tidak akan terpengaruh oleh instans pengujian Anda saat membangun penganalisis. Pertama kali Anda meluncurkan dengan cara ini, Visual Studio melakukan beberapa inisialisasi yang mirip dengan ketika Anda pertama kali meluncurkan Visual Studio setelah menginstalnya.

Buat proyek konsol lalu masukkan kode array ke dalam aplikasi konsol Anda Metode utama:

var b1 = new ImmutableArray<int>();
Console.WriteLine("b1.Length = {0}", b1.Length);
var b2 = new ImmutableArray<int> { 1, 2, 3, 4, 5 };
Console.WriteLine("b2.Length = {0}", b2.Length);

Baris kode dengan ImmutableArray memiliki berlekuk karena Anda perlu mendapatkan paket NuGet yang using tidak dapat diubah dan menambahkan pernyataan ke kode Anda. Tekan tombol penunjuk kanan pada simpul proyek di Penjelajah Solusi dan pilih Kelola Paket NuGet. Di manajer NuGet, ketik "Tidak Dapat Diubah" ke dalam kotak pencarian, dan pilih item System.Collections.Immutable (jangan pilih Microsoft.Bcl.Immutable) di panel kiri dan tekan tombol Instal di panel kanan. Menginstal paket menambahkan referensi ke referensi proyek Anda.

Anda masih melihat berlekuk merah di bawah ImmutableArray, jadi letakkan tanda sisipan di pengidentifikasi tersebut dan tekan Ctrl+. (titik) untuk memunculkan menu perbaikan yang disarankan dan pilih untuk menambahkan pernyataan yang sesuai.using

Simpan Semua dan Tutup instans kedua Visual Studio untuk saat ini agar Anda dalam keadaan bersih untuk melanjutkan.

Selesaikan penganalisis menggunakan edit dan lanjutkan

Dalam instans pertama Visual Studio, atur titik henti di awal metode Anda AnalyzeObjectCreation dengan menekan F9 dengan tanda sisipan pada baris pertama.

Luncurkan penganalisis Anda lagi dengan F5, dan di instans kedua Visual Studio, buka kembali aplikasi konsol yang Anda buat terakhir kali.

Anda kembali ke instans pertama Visual Studio di titik henti karena pengkompilasi Roslyn melihat ekspresi pembuatan Objek dan dipanggil ke penganalisis Anda.

Dapatkan simpul pembuatan objek. Langkah di atas baris yang mengatur objectCreation variabel dengan menekan F10, dan di Jendela Langsung mengevaluasi ekspresi "objectCreation.ToString()". Anda melihat bahwa simpul sintaks yang dirujuk variabel adalah kode "new ImmutableArray<int>()", hanya apa yang Anda cari.

Dapatkan objek ImmutableArray<T> Type. Anda perlu memeriksa apakah jenis yang dibuat adalah ImmutableArray. Pertama, Anda mendapatkan objek yang mewakili jenis ini. Anda memeriksa jenis menggunakan model semantik untuk memastikan Anda memiliki jenis yang tepat, dan Anda tidak membandingkan string dari ToString(). Masukkan baris kode berikut di akhir fungsi:

var immutableArrayOfTType =
    context.SemanticModel
           .Compilation
           .GetTypeByMetadataName("System.Collections.Immutable.ImmutableArray`1");

Anda menunjuk jenis generik dalam metadata dengan backtick (') dan jumlah parameter generik. Itu sebabnya Anda tidak melihat "... ImmutableArray<T>" dalam nama metadata.

Model semantik memiliki banyak hal berguna di dalamnya yang memungkinkan Anda mengajukan pertanyaan tentang simbol, aliran data, masa pakai variabel, dll. Roslyn memisahkan simpul sintaksis dari model semantik karena berbagai alasan rekayasa (performa, pemodelan kode yang salah, dll.). Anda ingin model kompilasi mencari informasi yang terkandung dalam referensi untuk perbandingan yang akurat.

Anda dapat menyeret penunjuk eksekusi kuning di sisi kiri jendela editor. Seret ke atas ke garis yang mengatur objectCreation variabel dan melangkahi baris kode baru Anda menggunakan F10. Jika Anda mengarahkan penunjuk mouse ke atas variabel immutableArrayOfType, Anda melihat bahwa kami menemukan jenis yang tepat dalam model semantik.

Dapatkan jenis ekspresi pembuatan objek. "Jenis" digunakan dalam beberapa cara dalam artikel ini, tetapi ini berarti jika Anda memiliki ekspresi "Foo baru", Anda perlu mendapatkan model Foo. Anda perlu mendapatkan jenis ekspresi pembuatan objek untuk melihat apakah itu adalah jenis ImmutableArray<T> . Gunakan model semantik lagi untuk mendapatkan informasi simbol untuk simbol jenis (ImmutableArray) dalam ekspresi pembuatan objek. Masukkan baris kode berikut di akhir fungsi:

var symbolInfo = context.SemanticModel.GetSymbolInfo(objectCreation.Type).Symbol as INamedTypeSymbol;

Karena penganalisis Anda perlu menangani kode yang tidak lengkap atau salah di buffer editor (misalnya, ada pernyataan yang hilang using ), Anda harus memeriksa menjadi symbolInfonull. Anda perlu mendapatkan jenis bernama (INamedTypeSymbol) dari objek informasi simbol untuk menyelesaikan analisis.

Bandingkan Jenis. Karena ada jenis umum terbuka dari T yang kita cari, dan jenis dalam kode adalah jenis generik konkret, Anda mengkueri informasi simbol untuk apa jenis dibangun dari (jenis generik terbuka) dan membandingkan hasilnya dengan immutableArrayOfTType. Masukkan yang berikut ini di akhir metode:

if (symbolInfo != null &&
    symbolInfo.ConstructedFrom.Equals(immutableArrayOfTType))
{}

Laporkan Diagnostik. Melaporkan diagnostik cukup mudah. Anda menggunakan Aturan yang dibuat untuk Anda dalam templat proyek, yang ditentukan sebelum metode Inisialisasi. Karena situasi dalam kode ini adalah kesalahan, Anda dapat mengubah baris yang menginisialisasi Aturan untuk mengganti DiagnosticSeverity.Warning (berlekuk hijau) dengan DiagnosticSeverity.Error (berlekuk merah). Aturan lainnya menginisialisasi dari sumber daya yang Anda edit di dekat awal panduan. Anda juga perlu melaporkan lokasi untuk squiggle, yang merupakan lokasi spesifikasi jenis ekspresi pembuatan objek. Masukkan kode ini di if blok:

context.ReportDiagnostic(Diagnostic.Create(Rule, objectCreation.Type.GetLocation()));

Fungsi Anda akan terlihat seperti ini (mungkin diformat secara berbeda):

private void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context)
{
    var objectCreation = (ObjectCreationExpressionSyntax)context.Node;
    var immutableArrayOfTType =
        context.SemanticModel
               .Compilation
               .GetTypeByMetadataName(
                   "System.Collections.Immutable.ImmutableArray`1");
    var symbolInfo = context.SemanticModel.GetSymbolInfo(objectCreation.Type).Symbol as
        INamedTypeSymbol;
    if (symbolInfo != null &&
        symbolInfo.ConstructedFrom.Equals(immutableArrayOfTType))
    {
        context.ReportDiagnostic(
            Diagnostic.Create(Rule, objectCreation.Type.GetLocation()));
    }
}

Hapus titik henti sehingga Anda dapat melihat penganalisis berfungsi (dan berhenti kembali ke instans pertama Visual Studio). Seret penunjuk eksekusi ke awal metode Anda, dan tekan F5 untuk melanjutkan eksekusi. Saat Anda beralih kembali ke instans kedua Visual Studio, pengkompilasi akan mulai memeriksa kode lagi, dan akan memanggil penganalisis Anda. Anda dapat melihat squiggle di bawah ImmutableType<int>.

Menambahkan "Perbaikan Kode" untuk Masalah Kode

Sebelum memulai, tutup instans kedua Visual Studio dan hentikan penelusuran kesalahan di instans pertama Visual Studio (tempat Anda mengembangkan penganalisis).

Tambahkan kelas baru. Gunakan menu pintasan (tombol penunjuk kanan) pada simpul proyek Anda di Penjelajah Solusi dan pilih untuk menambahkan item baru. Tambahkan kelas yang disebut BuildCodeFixProvider. Kelas ini perlu berasal dari CodeFixProvider, dan Anda harus menggunakan Ctrl+. (periode) untuk memanggil perbaikan kode yang menambahkan pernyataan yang benar.using Kelas ini juga perlu dianotasikan dengan ExportCodeFixProvider atribut, dan Anda harus menambahkan using pernyataan untuk menyelesaikan LanguageNames enum. Anda harus memiliki file kelas dengan kode berikut di dalamnya:

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;

namespace ImmutableArrayAnalyzer
{
    [ExportCodeFixProvider(LanguageNames.CSharp)]
    class BuildCodeFixProvider : CodeFixProvider
    {}

Stub keluar anggota turunan. Sekarang, letakkan tanda sisipan editor di pengidentifikasi CodeFixProvider dan tekan Ctrl+. (periode) untuk membagi implementasi untuk kelas dasar abstrak ini. Ini menghasilkan properti dan metode untuk Anda.

Implementasikan properti . Isi isi FixableDiagnosticIds properti get dengan kode berikut:

return ImmutableArray.Create(ImmutableArrayAnalyzerAnalyzer.DiagnosticId);

Roslyn menggabungkan diagnostik dan perbaikan dengan mencocokkan pengidentifikasi ini, yang hanyalah string. Templat proyek menghasilkan ID diagnostik untuk Anda, dan Anda bebas mengubahnya. Kode dalam properti hanya mengembalikan ID dari kelas penganalisis.

Metode RegisterCodeFixAsync mengambil konteks. Konteks ini penting karena perbaikan kode dapat berlaku untuk beberapa diagnostik, atau mungkin ada lebih dari satu masalah pada baris kode. Jika Anda mengetik "konteks." dalam isi metode , daftar penyelesaian IntelliSense akan menunjukkan kepada Anda beberapa anggota yang berguna. Ada anggota CancellationToken yang dapat Anda periksa untuk melihat apakah ada yang ingin membatalkan perbaikan. Ada anggota Dokumen yang memiliki banyak anggota yang berguna dan memungkinkan Anda masuk ke objek model proyek dan solusi. Ada anggota Rentang yang merupakan awal dan akhir lokasi kode yang ditentukan saat Anda melaporkan diagnostik.

Buat metode menjadi asinkron. Hal pertama yang perlu Anda lakukan adalah memperbaiki deklarasi metode yang async dihasilkan menjadi metode. Perbaikan kode untuk stubbing out implementasi kelas abstrak tidak menyertakan async kata kunci meskipun metode mengembalikan Task.

Dapatkan akar pohon sintaks. Untuk mengubah kode, Anda perlu menghasilkan pohon sintaks baru dengan perubahan yang dilakukan perbaikan kode Anda. Anda memerlukan Document dari konteks untuk memanggil GetSyntaxRootAsync. Ini adalah metode asinkron karena ada pekerjaan yang tidak diketahui untuk mendapatkan pohon sintaksis, mungkin termasuk mendapatkan file dari disk, mengurainya, dan membangun model kode Roslyn untuk itu. Antarmuka pengguna Visual Studio harus responsif selama waktu ini, yang menggunakan async diaktifkan. Ganti baris kode dalam metode dengan yang berikut:

var root = await context.Document
                        .GetSyntaxRootAsync(context.CancellationToken);

Temukan simpul dengan masalah ini. Anda meneruskan rentang konteks, tetapi simpul yang Anda temukan mungkin bukan kode yang harus Anda ubah. Diagnostik yang dilaporkan hanya menyediakan rentang untuk pengidentifikasi jenis (tempat squiggle berada), tetapi Anda perlu mengganti seluruh ekspresi pembuatan objek, termasuk new kata kunci di awal dan tanda kurung di akhir. Tambahkan kode berikut ke metode Anda (dan gunakan Ctrl+. untuk menambahkan using pernyataan untuk ):ObjectCreationExpressionSyntax

var objectCreation = root.FindNode(context.Span)
                         .FirstAncestorOrSelf<ObjectCreationExpressionSyntax>();

Daftarkan perbaikan kode Anda untuk UI bola lampu. Saat Anda mendaftarkan perbaikan kode, Roslyn akan menyambungkan ke antarmuka pengguna bola lampu Visual Studio secara otomatis. Pengguna akhir akan melihat mereka dapat menggunakan Ctrl+. (titik) ketika penganalisis Anda berkutat pada penggunaan konstruktor yang buruk.ImmutableArray<T> Karena penyedia perbaikan kode Anda hanya dijalankan ketika ada masalah, Anda dapat menganggap Anda memiliki ekspresi pembuatan objek yang Anda cari. Dari parameter konteks, Anda dapat mendaftarkan perbaikan kode baru dengan menambahkan kode berikut ke akhir RegisterCodeFixAsync metode:

context.RegisterCodeFix(
            CodeAction.Create("Use ImmutableArray<T>.Empty",
                              c => ChangeToImmutableArrayEmpty(objectCreation,
                                                               context.Document,
                                                               c)),
            context.Diagnostics[0]);

Anda perlu menempatkan tanda sisipan editor di pengidentifikasi, CodeAction, lalu gunakan Ctrl+. (titik) untuk menambahkan pernyataan yang sesuai using untuk jenis ini.

Kemudian letakkan tanda sisipan editor di ChangeToImmutableArrayEmpty pengidentifikasi dan gunakan Ctrl+. lagi untuk menghasilkan stub metode ini untuk Anda.

Cuplikan kode terakhir yang Anda tambahkan ini mendaftarkan perbaikan kode dengan meneruskan CodeAction dan ID diagnostik untuk jenis masalah yang ditemukan. Dalam contoh ini, hanya ada satu ID diagnostik yang disediakan kode ini untuk, sehingga Anda hanya dapat meneruskan elemen pertama dari array ID diagnostik. Saat Anda membuat CodeAction, Anda meneruskan teks yang harus digunakan UI bola lampu sebagai deskripsi perbaikan kode. Anda juga meneruskan fungsi yang mengambil CancellationToken dan mengembalikan Dokumen baru. Dokumen baru memiliki pohon sintaks baru yang menyertakan kode patch Anda yang memanggil ImmutableArray.Empty. Cuplikan kode ini menggunakan lambda sehingga dapat menutup simpul objectCreation dan Dokumen konteks.

Buat pohon sintaks baru. ChangeToImmutableArrayEmpty Dalam metode yang stubnya Anda buat sebelumnya, masukkan baris kode: ImmutableArray<int>.Empty;. Jika Anda melihat jendela alat Syntax Visualizer lagi, Anda dapat melihat sintaks ini adalah node SimpleMemberAccessExpression. Itulah yang diperlukan metode ini untuk membangun dan mengembalikan dalam Dokumen baru.

Perubahan ChangeToImmutableArrayEmpty pertama adalah menambahkan async sebelumnya Task<Document> karena generator kode tidak dapat mengasumsikan metode harus asinkron.

Isi isi dengan kode berikut sehingga metode Anda terlihat mirip dengan yang berikut ini:

private async Task<Document> ChangeToImmutableArrayEmpty(
    ObjectCreationExpressionSyntax objectCreation, Document document,
    CancellationToken c)
{
    var generator = SyntaxGenerator.GetGenerator(document);
    var memberAccess =
        generator.MemberAccessExpression(objectCreation.Type, "Empty");
    var oldRoot = await document.GetSyntaxRootAsync(c);
    var newRoot = oldRoot.ReplaceNode(objectCreation, memberAccess);
    return document.WithSyntaxRoot(newRoot);
}

Anda harus meletakkan tanda sisipan editor di SyntaxGenerator pengidentifikasi dan menggunakan Ctrl+. (titik) untuk menambahkan pernyataan yang sesuai using untuk jenis ini.

Kode ini menggunakan SyntaxGenerator, yang merupakan jenis yang berguna untuk membuat kode baru. Setelah mendapatkan generator untuk dokumen yang memiliki masalah kode, ChangeToImmutableArrayEmpty memanggil MemberAccessExpression, meneruskan jenis yang memiliki anggota yang ingin kita akses dan meneruskan nama anggota sebagai string.

Selanjutnya, metode mengambil akar dokumen, dan karena ini dapat melibatkan pekerjaan arbitrer dalam kasus umum, kode menunggu panggilan ini dan meneruskan token pembatalan. Model kode Roslyn tidak dapat diubah, seperti bekerja dengan string .NET; saat memperbarui string, Anda mendapatkan objek string baru sebagai gantinya. Ketika Anda memanggil ReplaceNode, Anda mendapatkan kembali node root baru. Sebagian besar pohon sintaksis dibagikan (karena tidak dapat diubah), tetapi objectCreation simpul diganti dengan simpul memberAccess , serta semua simpul induk hingga akar pohon sintaks.

Coba perbaikan kode Anda

Anda sekarang dapat menekan F5 untuk menjalankan penganalisis Anda dalam instans kedua Visual Studio. Buka proyek konsol yang Anda gunakan sebelumnya. Sekarang Anda akan melihat bola lampu muncul di mana ekspresi pembuatan objek baru Anda adalah untuk ImmutableArray<int>. Jika Anda menekan Ctrl+. (titik), maka Anda akan melihat perbaikan kode Anda, dan Anda akan melihat pratinjau perbedaan kode yang dihasilkan secara otomatis di antarmuka pengguna bola lampu. Roslyn menciptakan ini untukmu.

Tips Pro: Jika Anda meluncurkan instans kedua Visual Studio, dan Anda tidak melihat bola lampu dengan perbaikan kode Anda, maka Anda mungkin perlu menghapus cache komponen Visual Studio. Menghapus cache memaksa Visual Studio untuk memeriksa ulang komponen, jadi Visual Studio kemudian harus mengambil komponen terbaru Anda. Pertama, matikan instans kedua Visual Studio. Kemudian, di Windows Explorer, navigasikan ke %LOCALAPPDATA%\Microsoft\VisualStudio\16.0Roslyn\. (Perubahan "16.0" dari versi ke versi dengan Visual Studio.) Hapus subdirektori ComponentModelCache.

Berbicara video dan menyelesaikan proyek kode

Anda dapat melihat semua kode yang sudah selesai di sini. Sub folder DoNotUseImmutableArrayCollectionInitializer dan DoNotUseImmutableArrayCtor masing-masing memiliki file C# untuk menemukan masalah dan file C# yang mengimplementasikan perbaikan kode yang muncul di UI bola lampu Visual Studio. Perhatikan, kode jadi memiliki sedikit lebih banyak abstraksi untuk menghindari pengambilan objek jenis ImmutableArray<T> berulang-ulang. Ini menggunakan tindakan terdaftar berlapis untuk menyimpan objek jenis dalam konteks yang tersedia setiap kali sub tindakan (menganalisis pembuatan objek dan menganalisis inisialisasi pengumpulan) dijalankan.