Bagaimana Anda melakukan "fungsi sebaris" di C #? Saya rasa saya tidak mengerti konsepnya. Apakah mereka suka metode anonim? Suka fungsi lambda?
Catatan : Jawabannya hampir seluruhnya berkaitan dengan kemampuan fungsi sebaris , yaitu "pengoptimalan manual atau kompiler yang menggantikan situs fungsi panggilan dengan tubuh callee." Jika Anda tertarik pada fungsi anonim (alias lambda) , lihat jawaban @ jalf atau Apa ini 'Lambda' yang semua orang bicarakan? .
c#
optimization
inline
Dina
sumber
sumber
Jawaban:
Akhirnya di .NET 4.5, CLR memungkinkan seseorang untuk memberi petunjuk / menyarankan 1 metode inlining menggunakan
MethodImplOptions.AggressiveInlining
nilai. Ini juga tersedia di bagasi Mono (dilakukan hari ini).1 . Sebelumnya "kekuatan" digunakan di sini. Karena ada beberapa downvotes, saya akan mencoba mengklarifikasi istilah tersebut. Seperti dalam komentar dan dokumentasi,
The method should be inlined if possible.
Terutama mengingat Mono (yang terbuka), ada beberapa batasan teknis spesifik mono mempertimbangkan inlining atau yang lebih umum (seperti fungsi virtual). Secara keseluruhan, ya, ini adalah petunjuk untuk kompiler, tapi saya kira itulah yang diminta.sumber
Metode inline hanyalah pengoptimalan kompiler di mana kode fungsi digulirkan ke pemanggil.
Tidak ada mekanisme yang digunakan untuk melakukan ini dalam C #, dan mereka harus digunakan dengan hemat dalam bahasa di mana mereka didukung - jika Anda tidak tahu mengapa mereka harus digunakan di suatu tempat, mereka seharusnya tidak.
Sunting: Untuk memperjelas, ada dua alasan utama mereka perlu digunakan hemat:
Yang terbaik adalah membiarkan hal-hal sendirian dan membiarkan kompiler melakukan tugasnya, kemudian profil dan cari tahu apakah inline adalah solusi terbaik untuk Anda. Tentu saja, beberapa hal masuk akal untuk digarisbawahi (operator matematika khususnya), tetapi membiarkan kompiler menanganinya biasanya merupakan praktik terbaik.
sumber
Pembaruan: Per jawaban konrad.kruczynski , berikut ini benar untuk versi .NET hingga dan termasuk 4.0.
Anda bisa menggunakan kelas MethodImplAttribute untuk mencegah metode tidak diuraikan ...
... tetapi tidak ada cara untuk melakukan yang sebaliknya dan memaksanya untuk diuraikan.
sumber
GetExecutingAssembly
danGetCallingAssembly
dapat memberikan hasil yang berbeda tergantung pada apakah metode ini digarisbawahi. Memaksa suatu metode menjadi non-inline menghilangkan segala ketidakpastian.Anda mencampur dua konsep terpisah. Function inlining adalah pengoptimalan kompiler yang tidak berdampak pada semantik. Suatu fungsi berperilaku sama baik itu inline atau tidak.
Di sisi lain, fungsi lambda adalah murni konsep semantik. Tidak ada persyaratan tentang bagaimana mereka harus diimplementasikan atau dieksekusi, selama mereka mengikuti perilaku yang ditetapkan dalam spesifikasi bahasa. Mereka dapat diuraikan jika kompiler JIT terasa seperti itu, atau tidak jika tidak.
Tidak ada kata kunci inline dalam C #, karena ini merupakan optimasi yang biasanya dapat diserahkan kepada kompiler, terutama dalam bahasa JIT'ed. Kompiler JIT memiliki akses ke statistik runtime yang memungkinkannya untuk memutuskan apa yang harus digariskan jauh lebih efisien daripada yang Anda bisa saat menulis kode. Suatu fungsi akan digarisbawahi jika kompiler memutuskan, dan tidak ada yang dapat Anda lakukan dengan cara itu. :)
sumber
Apakah maksud Anda fungsi sebaris dalam arti C ++? Di mana isi fungsi normal secara otomatis disalin inline ke lokasi panggilan? Efek akhirnya adalah bahwa tidak ada panggilan fungsi yang sebenarnya terjadi saat memanggil fungsi.
Contoh:
Jika demikian maka tidak, tidak ada C # yang setara dengan ini.
Atau Apakah maksud Anda fungsi yang dideklarasikan dalam fungsi lain? Jika demikian maka ya, C # mendukung ini melalui metode anonim atau ekspresi lambda.
Contoh:
sumber
Cody benar, tetapi saya ingin memberikan contoh apa fungsi inline.
Katakanlah Anda memiliki kode ini:
The
compilerJust-In-Time optimizer dapat memilih untuk mengubah kode untuk menghindari berulang kali menempatkan panggilan ke OutputItem () pada stack, sehingga akan menjadi seperti jika Anda telah menulis kode seperti ini sebagai gantinya:Dalam hal ini, kita akan mengatakan fungsi OutputItem () diuraikan. Perhatikan bahwa itu mungkin melakukan ini bahkan jika OutputItem () dipanggil dari tempat lain juga.
Diedit untuk menunjukkan skenario yang lebih mungkin untuk digarisbawahi.
sumber
Ya Tepat, satu-satunya perbedaan adalah fakta mengembalikan nilai.
Penyederhanaan (tidak menggunakan ekspresi):
List<T>.ForEach
Mengambil tindakan, itu tidak mengharapkan hasil pengembalian.Jadi seorang
Action<T>
delegasi akan cukup .. katakan:sama dengan mengatakan:
perbedaannya adalah bahwa tipe param dan deklarasi delegasi disimpulkan oleh penggunaan dan kawat gigi tidak diperlukan pada metode inline sederhana.
Dimana sebagai
List<T>.Where
Mengambil fungsi, mengharapkan hasil.Jadi yang
Function<T, bool>
diharapkan:yang sama dengan:
Anda juga dapat mendeklarasikan metode ini secara inline dan menandainya dengan variabel IE:
atau
Saya harap ini membantu.
sumber
Ada saat-saat di mana saya ingin memaksakan kode dimasukkan.
Sebagai contoh jika saya memiliki rutinitas yang kompleks di mana ada sejumlah besar keputusan yang dibuat dalam blok yang sangat iteratif dan keputusan itu menghasilkan tindakan yang serupa tetapi sedikit berbeda untuk dilakukan. Pertimbangkan misalnya, pembanding pengurutan yang kompleks (non-driven DB) di mana algorythm pengurutan mengurutkan elemen berdasarkan sejumlah kriteria yang tidak terkait seperti yang mungkin dilakukan jika mereka mengurutkan kata-kata berdasarkan kriteria gramatik dan semantik untuk bahasa cepat. sistem pengenalan. Saya akan cenderung menulis fungsi pembantu untuk menangani tindakan tersebut untuk menjaga keterbacaan dan modularitas kode sumber.
Saya tahu bahwa fungsi-fungsi pembantu itu harus dimasukkan karena itulah cara kode akan ditulis jika tidak pernah harus dipahami oleh manusia. Saya pasti ingin memastikan dalam hal ini bahwa tidak ada fungsi yang memanggil overhead.
sumber
Pernyataan "yang terbaik adalah membiarkan hal-hal ini sendirian dan membiarkan kompiler melakukan pekerjaan .." (Cody Brocious) benar-benar sia-sia. Saya telah memprogram kode permainan berkinerja tinggi selama 20 tahun, dan saya belum menemukan kompiler yang 'cukup pintar' untuk mengetahui kode mana yang harus digariskan (fungsi) atau tidak. Akan berguna untuk memiliki pernyataan "inline" dalam c #, kebenarannya adalah bahwa kompiler tidak memiliki semua informasi yang diperlukan untuk menentukan fungsi mana yang harus selalu diuraikan atau tidak tanpa petunjuk "inline". Yakin jika fungsinya kecil (accessor) maka itu mungkin secara otomatis diuraikan, tetapi bagaimana jika itu adalah beberapa baris kode? Nonesense, kompiler tidak memiliki cara untuk mengetahui, Anda tidak bisa membiarkannya sampai ke kompiler untuk kode yang dioptimalkan (di luar algoritma).
sumber
Saya tahu pertanyaan ini tentang C #. Namun, Anda dapat menulis fungsi sebaris di .NET dengan F #. lihat: Penggunaan `inline` dalam F #
sumber
Tidak, tidak ada konstruksi seperti itu di C #, tetapi .NET JIT compiler dapat memutuskan untuk melakukan panggilan fungsi inline pada waktu JIT. Tetapi saya sebenarnya tidak tahu apakah itu benar-benar melakukan optimasi seperti itu.
(Saya pikir seharusnya :-))
sumber
Jika rakitan Anda akan ngen-ed, Anda mungkin ingin melihat di TargetedPatchingOptOut. Ini akan membantu ngen memutuskan apakah akan menggunakan metode inline. Referensi MSDN
Ini masih hanya petunjuk deklaratif untuk mengoptimalkan, bukan perintah imperatif.
sumber
Ekspresi Lambda adalah fungsi sebaris! Saya pikir, bahwa C # tidak memiliki atribut tambahan seperti inline atau sesuatu seperti itu!
sumber
C # tidak mendukung metode sebaris (atau fungsi) dengan cara bahasa dinamis seperti python lakukan. Namun metode anonim dan lambda dapat digunakan untuk tujuan yang sama termasuk ketika Anda perlu mengakses variabel dalam metode yang mengandung seperti pada contoh di bawah ini.
sumber