Praktik terbaik untuk menandai metode yang disebut melalui refleksi?


11

Perangkat lunak kami memiliki beberapa kelas yang harus ditemukan secara dinamis melalui refleksi. Kelas-kelas semua memiliki konstruktor dengan tanda tangan tertentu di mana kode refleksi instantiate objek.
Namun, ketika seseorang memeriksa apakah metode ini dirujuk (misalnya melalui Visual Code Code Lens), referensi melalui refleksi tidak dihitung. Orang-orang dapat kehilangan referensi mereka dan menghapus (atau mengubah) metode yang tampaknya tidak digunakan.

Bagaimana seharusnya kita menandai / mendokumentasikan metode yang dimaksudkan untuk dipanggil melalui refleksi?

Idealnya, metode ini harus ditandai sedemikian rupa sehingga kolega dan Visual Studio / Roslyn dan alat otomatis lainnya 'melihat' bahwa metode ini dimaksudkan untuk dipanggil melalui refleksi.

Saya tahu dua opsi yang bisa kita gunakan tetapi keduanya tidak cukup memuaskan. Karena Visual Studio tidak dapat menemukan referensi:

  • Gunakan Atribut khusus dan tandai konstruktor dengan atribut ini.
    • Masalahnya adalah bahwa atribut Atribut tidak dapat menjadi referensi metode, oleh karena itu konstruktor masih akan menunjukkan memiliki 0 referensi.
    • Kolega yang tidak terbiasa dengan atribut khusus mungkin akan mengabaikannya.
    • Keuntungan dari pendekatan saya saat ini adalah bagian refleksi dapat menggunakan atribut untuk menemukan konstruktor yang harus dipanggil.
  • Gunakan komentar untuk mendokumentasikan bahwa metode / konstruktor dimaksudkan untuk dipanggil melalui refleksi.
    • Alat otomatis mengabaikan komentar (dan rekan mungkin juga melakukannya).
    • Komentar Dokumentasi Xml dapat digunakan untuk meminta Visual Studio menghitung referensi tambahan ke metode / konstruktor:
      Biarkan MyPluginkelas yang konstruktornya dipanggil melalui refleksi. Asumsikan kode refleksi yang dicari mencari konstruktor yang mengambil intparameter. Dokumentasi berikut membuat lensa kode menunjukkan konstruktor yang memiliki 1 referensi:
      /// <see cref="MyPlugin.MyPlugin(int)"/> is invoked via reflection

Pilihan mana yang lebih baik?
Apa praktik terbaik untuk menandai metode / konstruktor yang dimaksudkan untuk dipanggil melalui refleksi?


Untuk lebih jelasnya, ini untuk beberapa jenis sistem plugin, kan?
whatsisname

2
Anda berasumsi bahwa rekan kerja Anda akan mengabaikan atau melewatkan semua yang Anda lakukan ... Anda tidak dapat mencegah kode dari ketidakefektifan di tempat kerja. Bagi saya, mendokumentasikan sepertinya cara yang lebih mudah, lebih bersih, lebih murah, dan lebih baik. Kalau tidak, tidak akan ada pemrograman deklaratif.
Laiv

1
Resharper memiliki atribut [UsedImplictly].
CodesInChaos

4
Saya kira opsi komentar doc Xml mungkin adalah pilihan terbaik Anda. Ini pendek, mendokumentasikan diri sendiri, dan tidak memerlukan "peretasan" atau definisi tambahan.
Doc Brown

2
Pilihan lain untuk komentar dokumentasi xml. Jika Anda tetap membuat dokumentasi, itu harus menonjol dalam dokumentasi yang dihasilkan.
Frank Hileman

Jawaban:


12

Kombinasi dari solusi yang disarankan:

  • Gunakan tag Dokumentasi XML untuk mendokumentasikan bahwa konstruktor / metode dipanggil melalui refleksi.
    Ini harus menjelaskan penggunaan yang dimaksudkan untuk kolega (dan masa depan saya sendiri).
  • Gunakan 'trik' melalui <see>-tag untuk meningkatkan jumlah referensi untuk konstruktor / metode.
    Ini membuat lensa kode itu dan menemukan referensi menunjukkan bahwa konstruktor / metode direferensikan.
  • Beranotasi dengan Resharper UsedImplicitlyAttribute
    • Resharper adalah standar de facto dan [UsedImplicitly]memiliki semantik yang dimaksudkan.
    • Mereka yang tidak menggunakan Resharper dapat menginstal Annotasi JetBrains ReSharper via NuGet:
      PM> Install-Package JetBrains.Annotations.
  • Jika ini adalah metode pribadi dan Anda menggunakan analisis kode Visual Studio, gunakan SupressMessageAttributeuntuk pesan tersebut CA1811: Avoid uncalled private code.

Sebagai contoh:

class MyPlugin
{
    /// <remarks>
    /// <see cref="MyPlugin.MyPlugin(int)"/> is called via reflection.
    /// </remarks>
    [JetBrains.Annotations.UsedImplicitly]
    public MyPlugin(int arg)
    {
        throw new NotImplementedException();
    }

    /// <remarks>
    /// <see cref="MyPlugin.MyPlugin(string)"/> is called via reflection.
    /// </remarks>
    [JetBrains.Annotations.UsedImplicitly]
    [System.Diagnostics.CodeAnalysis.SuppressMessage(
        "Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode",
        Justification = "Constructor is called via reflection")]
    private MyPlugin(string arg)
    {
        throw new NotImplementedException();
    }
}

Solusi menganugerahkan maksud penggunaan konstruktor untuk pembaca manusia dan 3 sistem analisis kode statis yang paling banyak digunakan dengan C # dan Visual Studio.
The downside adalah bahwa baik komentar dan satu atau dua penjelasan mungkin tampak agak berlebihan.


Perhatikan ada juga MeansImplicitUseAttributeyang bisa digunakan untuk membuat atribut sendiri yang punya UsedImplicitlyefek. Ini dapat mengurangi banyak noise atribut dalam situasi yang tepat.
Dave Cousineau

Tautan ke JetBrains rusak.
John Zabroski

5

Saya belum pernah mengalami masalah ini dalam proyek Net, tetapi saya secara teratur memiliki masalah yang sama dengan proyek Java. Pendekatan saya yang biasa ada adalah menggunakan @SuppressWarnings("unused")anotasi menambahkan komentar yang menjelaskan mengapa (mendokumentasikan alasan untuk menonaktifkan peringatan adalah bagian dari gaya kode standar saya - setiap kali kompiler tidak dapat menemukan sesuatu, saya berasumsi bahwa kemungkinan manusia akan berjuang terlalu). Ini memiliki keuntungan secara otomatis memastikan alat analisis statis menyadari bahwa kode tersebut tidak seharusnya memiliki referensi langsung, dan memberikan alasan terperinci bagi pembaca manusia.

Setara dengan C # untuk Java @SuppressWarningsadalah SuppressMessageAttribute. Untuk metode pribadi, Anda dapat menggunakan pesan CA1811: Hindari kode pribadi yang tidak pantas ; misalnya:

class MyPlugin
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage(
        "Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode",
        Justification = "Constructor is called via reflection")]
    private MyPlugin(int arg)
    {
        throw new NotImplementedException();
    }
}

(Saya tidak tahu, tetapi anggap bahwa CLI mendukung atribut yang mirip dengan Java yang saya sebutkan; jika ada yang tahu apa itu, silakan edit jawaban saya sebagai referensi untuk itu ...)
Jules


1
Saya baru-baru ini menemukan bahwa melakukan tes dan cakupan mesuring (dalam java) adalah cara yang baik untuk mengetahui apakah suatu blok kode benar-benar tidak digunakan. Lalu saya bisa menghapusnya atau melihat mengapa tidak digunakan (jika saya mengharapkan yang sebaliknya). Saat mencari adalah ketika saya lebih memperhatikan komentar.
Laiv

Ada SuppressMessageAttribute( msdn.microsoft.com/en-us/library/… ). Pesan yang paling dekat adalah CA1811: Avoid uncalled private code( msdn.microsoft.com/en-us/library/ms182264.aspx ); Saya belum menemukan pesan untuk kode publik.
Kasper van den Berg

2

Alternatif untuk mendokumentasikan adalah memiliki unit test untuk memastikan bahwa panggilan refleksi berjalan dengan sukses.

Dengan begitu, jika seseorang mengubah atau menghapus metode proses build / test Anda akan memberi tahu Anda bahwa Anda telah merusak sesuatu.


0

Nah tanpa melihat kode Anda, sepertinya ini akan menjadi tempat yang baik untuk memperkenalkan beberapa warisan. Mungkin metode virtual atau abstrak yang dapat memanggil konstruktor dari kelas-kelas ini? Jika Anda adalah metode yang Anda coba tandai hanyalah konstruktor, maka Anda benar-benar mencoba untuk menandai kelas dan bukan metode ya? Sesuatu yang telah saya lakukan di masa lalu untuk menandai kelas adalah membuat antarmuka kosong. Kemudian alat inspeksi kode dan refactoring dapat mencari kelas yang mengimplementasikan antarmuka.


Warisan yang normal biasanya adalah jalannya. Dan kelas-kelas itu memang terkait dengan warisan. Tetapi menciptakan contoh baru di luar warisan. Selain itu, saya mengandalkan 'pewarisan' metode statis, dan karena C # tidak mendukung slot kelas; ada jalan keluar, yang saya gunakan, tapi itu di luar cakupan komentar ini.
Kasper van den Berg
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.