Dinamis dalam C #: resep penggunaan

Ini adalah bagian terakhir dari seri Dynamic Language Runtime . Artikel sebelumnya:

  1. Detail dinamis: game penyamar penyusun, kebocoran memori, nuansa kinerja . Artikel ini membahas cache DLR secara terperinci dan poin-poin yang penting bagi pengembang.
  2. DLL DLL . Tinjauan umum teknologi, diseksi DynamicMetaObject, dan instruksi singkat tentang cara membuat kelas dinamis Anda sendiri.

Dalam artikel singkat ini, kita akhirnya akan menganalisis kasus-kasus utama penggunaan dinamis dalam kehidupan nyata: ketika Anda tidak dapat melakukannya tanpa itu dan kapan hal itu dapat sangat memudahkan keberadaan.



Ketika dinamis sangat diperlukan


Tidak ada kasus seperti itu. Anda selalu dapat menulis kode serupa dalam fungsionalitas dalam gaya statis, satu-satunya perbedaan adalah kemudahan membaca dan jumlah kode. Misalnya, saat bekerja dengan objek COM, alih-alih dinamis, Anda bisa menggunakan refleksi.

Ketika dinamis bermanfaat


Bekerja dengan objek COM


Pertama-tama, ini, tentu saja, bekerja dengan objek COM, yang karenanya semua ini dimulai. Bandingkan kode yang diperoleh dengan dinamis dan refleksi:

dynamic instance = Activator.CreateInstance(type); instance.Run("Notepad.exe"); 

 var instance = Activator.CreateInstance(type); type.InvokeMember("Run", BindingFlags.InvokeMethod, null, instance, new[] { "Notepad.exe" }); 

Sebagai aturan, untuk bekerja dengan objek COM melalui refleksi, Anda harus membuat kelas bercabang dengan pembungkus untuk setiap metode / properti. Ada juga barang yang kurang jelas seperti kemampuan untuk tidak mengisi parameter yang tidak Anda butuhkan (wajib dari sudut pandang objek COM) saat memanggil metode melalui dinamis .

Bekerja dengan konfigurasi


Contoh buku teks lain sedang bekerja dengan konfigurasi, seperti XML . Tanpa dinamis :

 XElement person = XElement.Parse(xml); Console.WriteLine( $"{person.Descendants("FirstName").FirstOrDefault().Value} {person.Descendants("LastName").FirstOrDefault().Value}" ); 

Dengan dinamis:

 dynamic person = DynamicXml.Parse(xml); Console.WriteLine( $"{person.FirstName} {person.LastName}" ); 

Tentu saja, untuk ini Anda perlu mengimplementasikan kelas dinamis Anda sendiri. Sebagai alternatif dari daftar pertama, Anda dapat menulis kelas yang akan berfungsi seperti ini:

 var person = StaticXml.Parse(xml); Console.WriteLine( $"{person.GetElement("FirstName")} {person.GetElement("LastName")}" ); 

Tapi, Anda lihat, ini terlihat jauh lebih elegan daripada melalui dinamis .

Bekerja dengan sumber daya eksternal


Paragraf sebelumnya dapat digeneralisasi untuk tindakan apa pun dengan sumber daya eksternal. Kami selalu memiliki dua alternatif: menggunakan dinamis untuk mendapatkan kode dalam gaya C # asli atau mengetik statis dengan "garis ajaib". Mari kita lihat contoh dengan permintaan REST API . Dengan dinamis, Anda dapat menulis ini:

 dynamic dynamicRestApiClient = new DynamicRestApiClient("http://localhost:18457/api"); dynamic catsList = dynamicRestApiClient.CatsList; 

Di mana kelas dinamis kami akan mengirimkan permintaan formulir atas permintaan properti

 [GET] http://localhost:18457/api/catslist 

Kemudian dia membatalkan desisialisasi dan mengembalikan kepada kami sejumlah kucing yang sudah siap untuk digunakan. Tanpa dinamis, akan terlihat seperti ini:

 var restApiClient = new RestApiClient("http://localhost:18457/api"); var catsListJson = restApiClient.Get("catsList"); var deserializedCatsList = JsonConvert.DeserializeObject<Cat[]>(catsListJson); 

Penggantian Refleksi


Dalam contoh sebelumnya, Anda mungkin memiliki pertanyaan: mengapa dalam satu kasus kami deserializing nilai kembali ke jenis tertentu, dan yang lain tidak? Faktanya adalah bahwa dalam pengetikan statis kita perlu secara eksplisit melemparkan objek ke tipe Cat untuk bekerja dengannya. Dalam kasus dinamis , cukup untuk deserialize JSON menjadi array objek di dalam kelas dinamis kami dan mengembalikan objek [] dari itu, karena dinamis mengurus refleksi. Saya akan memberikan dua contoh bagaimana ini bekerja:

 dynamic deserialized = JsonConvert.DeserializeObject<object>(serialized); var name = deserialized.Name; var lastName = deserialized.LastName; 

 Attribute[] attributes = type.GetCustomAttributes(false).OfType<Attribute>(); dynamic attribute = attributes.Single(x => x.GetType().Name == "DescriptionAttribute"); var description = attribute.Description; 

Prinsip yang sama seperti ketika bekerja dengan objek COM.

Pengunjung


Dengan menggunakan dinamis, Anda dapat menerapkan pola ini dengan sangat elegan. Alih-alih seribu kata:

 public static void DoSomeWork(Item item) { InternalDoSomeWork((dynamic) item); } private static void InternalDoSomeWork(Item item) { throw new Exception("Couldn't find handler for " + item.GetType()); } private static void InternalDoSomeWork(Sword item) { //do some work with sword } private static void InternalDoSomeWork(Shield item) { //do some work with shield } public class Item { } public class Sword : Item {} public class Shield : Item {} 

Sekarang, ketika melewati objek bertipe Sword ke metode DoSomeWork , metode InternalDoSomeWork (item Sword) akan dipanggil.

Kesimpulan


Kelebihan menggunakan dinamis :

  • Dapat digunakan untuk pembuatan prototipe cepat: dalam banyak kasus, jumlah kode boilerplate berkurang
  • Sebagai aturan, ini meningkatkan keterbacaan dan estetika (karena transisi dari "garis ajaib" ke gaya bahasa asli) dari kode
  • Meskipun pendapat tersebar luas, berkat mekanisme caching, overhead kinerja yang signifikan dalam kasus umum tidak muncul

Kontra menggunakan dinamis:

  • Ada nuansa tidak jelas yang terkait dengan memori dan kinerja.
  • Dengan dukungan dan pembacaan kelas dinamis seperti itu, Anda perlu memahami dengan baik apa yang sedang terjadi
  • Programmer tidak memiliki pemeriksaan tipe dan semua jaminan kesehatan disediakan oleh kompiler

Kesimpulan


Menurut pendapat saya, pengembang akan menerima keuntungan terbesar dari menggunakan dinamis dalam situasi berikut:

  • Saat membuat prototipe
  • Dalam proyek kecil / rumah di mana biaya kesalahan rendah
  • Dalam utilitas ukuran kode kecil yang tidak menyiratkan waktu jangka panjang. Jika utilitas Anda dieksekusi dalam kasus terburuk selama beberapa detik, biasanya tidak perlu memikirkan kebocoran memori dan penurunan kinerja

Paling tidak kontroversial adalah penggunaan dinamis dalam proyek kompleks dengan basis kode besar - di sini lebih baik menghabiskan waktu menulis pembungkus statis, sehingga meminimalkan jumlah momen yang tidak jelas.

Jika Anda bekerja dengan objek COM atau domain dalam layanan / produk yang menyiratkan waktu kerja terus menerus yang lama, lebih baik untuk tidak menggunakan dinamis , meskipun fakta bahwa itu dibuat untuk kasus seperti itu. Bahkan jika Anda benar-benar tahu apa dan bagaimana melakukan dan tidak pernah melakukan kesalahan, cepat atau lambat pengembang baru mungkin datang yang tidak mengetahui hal ini. Hasilnya kemungkinan adalah kebocoran memori yang sulit dihitung.

Source: https://habr.com/ru/post/id470355/


All Articles