Saya punya sepotong kecil kode yang mengurai nilai indeks untuk menentukan input sel ke dalam Excel. Itu membuatku berpikir ...
Apa perbedaannya
xlsSheet.Write("C" + rowIndex.ToString(), null, title);
dan
xlsSheet.Write(string.Format("C{0}", rowIndex), null, title);
Apakah yang satu "lebih baik" dari yang lain? Dan mengapa?
Jawaban:
Sebelum C # 6
Sejujurnya, menurut saya versi pertama lebih sederhana - meskipun saya menyederhanakannya menjadi:
Saya menduga jawaban lain mungkin berbicara tentang kinerja hit, tetapi jujur saja itu akan minimal jika ada - dan versi penggabungan ini tidak perlu mengurai string format.
String format sangat bagus untuk tujuan pelokalan dll, tetapi dalam kasus seperti penggabungan ini lebih sederhana dan berfungsi dengan baik.
Dengan C # 6
Interpolasi string membuat banyak hal lebih mudah dibaca di C # 6. Dalam hal ini, kode kedua Anda menjadi:
yang mungkin merupakan pilihan terbaik, IMO.
sumber
xlsSheet.Write($"C{rowIndex}", null, title);
Preferensi awal saya (berasal dari latar belakang C ++) adalah untuk String.Format. Saya menjatuhkan ini nanti karena alasan berikut:
- Penggabungan string memungkinkan untuk nilai null,String.Format
tidak. Menulis "s1 + null + s2
" tidak merusak, itu hanya memperlakukan nilai null sebagai String.Empty. Nah, ini mungkin tergantung pada skenario spesifik Anda - ada kasus di mana Anda menginginkan kesalahan alih-alih mengabaikan Nama Depan null secara diam-diam. Namun bahkan dalam situasi ini saya pribadi lebih suka memeriksa nulls sendiri dan melemparkan kesalahan tertentu daripada ArgumentNullException standar yang saya dapatkan dari String.Format.Idenya adalah kompiler .NET cukup pintar untuk mengonversi potongan kode ini:
untuk ini:
Apa yang terjadi di bawah tenda String.Concat mudah ditebak (gunakan Reflector). Objek dalam array diubah menjadi string mereka melalui ToString (). Kemudian total panjang dihitung dan hanya satu string yang dialokasikan (dengan total panjang). Akhirnya, setiap string disalin ke string yang dihasilkan melalui wstrcpy di beberapa bagian kode yang tidak aman.
Alasannya
String.Concat
jauh lebih cepat? Nah, kita semua dapat melihat apa yangString.Format
sedang dilakukan - Anda akan terkejut dengan jumlah kode yang diperlukan untuk memproses format string. Di atas ini (saya telah melihat komentar tentang konsumsi memori),String.Format
menggunakan StringBuilder secara internal. Begini caranya:StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
Jadi untuk setiap argumen yang lolos, itu cadangan 8 karakter. Jika argumennya adalah nilai satu digit, maka sayang sekali, kita memiliki beberapa ruang yang terbuang. Jika argumennya adalah objek khusus yang mengembalikan beberapa teks panjang
ToString()
, maka mungkin ada beberapa realokasi yang diperlukan (skenario terburuk, tentu saja).Dibandingkan dengan ini, penggabungan hanya membuang-buang ruang dari larik objek (tidak terlalu banyak, mengingat itu adalah larik referensi). Tidak ada parsing untuk penentu format dan tidak ada StringBuilder perantara. Overhead tinju / unboxing ada di kedua metode.
Satu-satunya alasan saya menggunakan String.Format adalah ketika pelokalan dilibatkan. Menempatkan string format dalam sumber daya memungkinkan Anda untuk mendukung bahasa yang berbeda tanpa mengotak-atik kode (pikirkan tentang skenario di mana nilai yang diformat berubah urutan bergantung pada bahasa, yaitu "setelah {0} jam dan {1} menit" mungkin terlihat sangat berbeda dalam bahasa Jepang: ).
Untuk meringkas posting pertama saya (dan cukup panjang):
ToString()
panggilan apa punToString()
panggilan sendiri untuk menghindari tinju (saya agak bias terhadap keterbacaan) - sama seperti opsi pertama dalam pertanyaan AndaString.Format()
memiliki keunggulan.sumber
string.Format
"aman" saat menggunakan ReSharper; artinya, ini seaman kode lain yang dapat digunakan [secara tidak benar]. 2)string.Format
tidak memungkinkan untuk "aman"null
:string.Format("A{0}B", (string)null)
hasil dalam "AB". 3) Saya jarang peduli dengan tingkat kinerja ini (dan untuk itu, ini adalah hari yang langka ketika saya mundurStringBuilder
) ...string s = "This " + MyMethod(arg) + " is a test";
dikompilasi keString.Concat()
panggilan dalam mode Rilis.Saya pikir opsi pertama lebih mudah dibaca dan itu harus menjadi perhatian utama Anda.
string.Format menggunakan StringBuilder di bawah kapnya (periksa dengan reflektor ) sehingga tidak akan memiliki manfaat kinerja apa pun kecuali Anda melakukan penggabungan dalam jumlah yang signifikan. Ini akan lebih lambat untuk skenario Anda tetapi kenyataannya adalah keputusan pengoptimalan kinerja mikro ini sebagian besar waktu tidak sesuai dan Anda harus benar-benar fokus pada keterbacaan kode Anda kecuali Anda berada dalam lingkaran.
Apa pun caranya, tulis agar terbaca terlebih dahulu, lalu gunakan profiler kinerja untuk mengidentifikasi hotspot Anda jika Anda merasa benar-benar memiliki masalah kinerja.
sumber
Untuk kasus sederhana di mana itu adalah rangkaian tunggal sederhana, saya merasa itu tidak sebanding dengan kerumitannya
string.Format
(dan saya belum menguji, tetapi saya curiga untuk kasus sederhana seperti ini,string.Format
mungkin sedikit lebih lambat, apa dengan format string parsing dan semua). Seperti Jon Skeet, saya lebih suka untuk tidak menelepon secara eksplisit.ToString()
, karena itu akan dilakukan secara implisit olehstring.Concat(string, object)
kelebihan beban, dan saya pikir kodenya terlihat lebih bersih dan lebih mudah dibaca tanpanya.Tetapi untuk lebih dari beberapa rangkaian (berapa banyak yang subjektif), saya pasti lebih suka
string.Format
. Pada titik tertentu saya berpikir bahwa keterbacaan dan kinerja menderita yang tidak perlu dengan penggabungan.Jika ada banyak parameter untuk format string (sekali lagi, "banyak" adalah subjektif), saya biasanya lebih suka menyertakan indeks yang diberi komentar pada argumen pengganti, jangan sampai saya kehilangan jejak nilai mana yang menuju ke parameter mana. Contoh yang dibuat-buat:
Memperbarui
Itu terjadi kepada saya bahwa contoh saya berikan adalah sedikit membingungkan, karena tampaknya bahwa saya telah digunakan baik Rangkaian dan
string.Format
di sini. Dan ya, secara logis dan leksikal, itulah yang telah saya lakukan. Tapi penggabungan semua akan dioptimalkan oleh kompiler 1 , karena semuanya adalah string literal. Jadi pada saat run-time, akan ada satu string. Jadi saya rasa saya harus mengatakan bahwa saya lebih suka menghindari banyak penggabungan pada waktu berjalan .Tentu saja, sebagian besar topik ini sudah kedaluwarsa, kecuali Anda masih terjebak menggunakan C # 5 atau yang lebih lama. Sekarang kami memiliki string yang diinterpolasi , yang agar terbaca, jauh lebih unggul
string.Format
, di hampir semua kasus. Hari-hari ini, kecuali saya hanya menggabungkan nilai langsung ke awal atau akhir string literal, saya hampir selalu menggunakan interpolasi string. Hari ini, saya akan menulis contoh saya sebelumnya seperti ini:Anda kehilangan penggabungan waktu kompilasi dengan cara ini. Setiap string yang diinterpolasi diubah menjadi panggilan
string.Format
oleh kompiler, dan hasilnya digabungkan pada waktu proses. Itu berarti ini adalah pengorbanan kinerja run-time untuk keterbacaan. Seringkali, ini adalah pengorbanan yang berharga, karena penalti run-time dapat diabaikan. Namun, dalam kode kinerja kritis, Anda mungkin perlu membuat profil solusi yang berbeda.1 Anda dapat melihat ini di spesifikasi C # :
Anda juga dapat memverifikasinya dengan sedikit kode:
sumber
String.Format()
Jika string Anda lebih kompleks dengan banyak variabel yang digabungkan, maka saya akan memilih string.Format (). Tetapi untuk ukuran string dan jumlah variabel yang digabungkan dalam kasus Anda, saya akan menggunakan versi pertama Anda, ini lebih sederhana .
sumber
Saya telah melihat String.Format (menggunakan Reflector) dan itu benar-benar membuat StringBuilder kemudian memanggil AppendFormat di atasnya. Jadi lebih cepat daripada concat untuk beberapa pengadukan. Paling cepat (saya percaya) akan membuat StringBuilder dan melakukan panggilan ke Tambahkan secara manual. Tentu saja jumlah "banyak" untuk menebak. Saya akan menggunakan + (sebenarnya & karena saya kebanyakan programmer VB) untuk sesuatu yang sederhana seperti contoh Anda. Karena semakin kompleks, saya menggunakan String.Format. Jika ada BANYAK variabel maka saya akan menggunakan StringBuilder dan Tambahkan, misalnya, kami memiliki kode yang membangun kode, di sana saya menggunakan satu baris kode aktual untuk menghasilkan satu baris kode yang dihasilkan.
Tampaknya ada beberapa spekulasi tentang berapa banyak string yang dibuat untuk masing-masing operasi ini, jadi mari kita ambil beberapa contoh sederhana.
"C" sudah menjadi string.
rowIndex.ToString () membuat string lain. (@manohard - tidak ada tinju dari rowIndex yang akan terjadi)
Kemudian kita mendapatkan string terakhir.
Jika kita ambil contoh
maka kita memiliki "C {0}" sebagai string
rowIndex mendapat kotak untuk diteruskan ke fungsi
Sebuah
pembuat string baru dibuat AppendFormat dipanggil pada pembuat string - Saya tidak tahu detail bagaimana fungsi AppendFormat tapi mari kita asumsikan itu sangat efisien, masih harus mengubah rowIndex dalam kotak menjadi string.
Kemudian ubah pembuat string menjadi string baru.
Saya tahu bahwa StringBuilders berusaha mencegah salinan memori yang tidak berguna terjadi tetapi String.Format masih berakhir dengan overhead tambahan dibandingkan dengan penggabungan biasa.
Jika sekarang kita ambil contoh dengan beberapa string lagi
kami memiliki 6 string untuk memulai, yang akan sama untuk semua kasus.
Menggunakan penggabungan kami juga memiliki 4 string perantara ditambah hasil akhir. Ini adalah hasil antara yang dihilangkan dengan menggunakan String, Format (atau StringBuilder).
Ingatlah bahwa untuk membuat setiap string perantara, string sebelumnya harus disalin ke lokasi memori baru, bukan hanya alokasi memori yang berpotensi lambat.
sumber
Saya suka String.Format karena dapat membuat teks Anda yang diformat lebih mudah diikuti dan dibaca daripada penggabungan sebaris, juga jauh lebih fleksibel memungkinkan Anda untuk memformat parameter Anda, namun untuk penggunaan singkat seperti milik Anda, saya tidak melihat masalah tentang penggabungan.
Untuk penggabungan di dalam loop atau dalam string besar, Anda harus selalu mencoba menggunakan kelas StringBuilder.
sumber
Contoh itu mungkin terlalu sepele untuk melihat perbedaannya. Faktanya, saya pikir dalam banyak kasus kompiler dapat mengoptimalkan perbedaan apa pun sama sekali.
Namun, jika saya harus menebak, saya akan memberikan
string.Format()
keunggulan untuk skenario yang lebih rumit. Tapi itu lebih merupakan firasat bahwa kemungkinan akan melakukan pekerjaan yang lebih baik dengan menggunakan buffer daripada menghasilkan beberapa string yang tidak dapat diubah, dan tidak berdasarkan data nyata apa pun.sumber
Saya setuju dengan banyak poin di atas, poin lain yang saya percaya harus disebutkan adalah pemeliharaan kode. string.Format memungkinkan untuk lebih mudah mengubah kode.
yaitu saya memiliki pesan
"The user is not authorized for location " + location
atau"The User is not authorized for location {0}"
jika saya ingin mengubah pesan menjadi:
location + " does not allow this User Access"
atau"{0} does not allow this User Access"
dengan string.Format yang harus saya lakukan adalah mengubah string. untuk penggabungan saya harus mengubah pesan itu
jika digunakan di banyak tempat bisa menghemat jatah waktu.
sumber
Saya mendapat kesan bahwa string.format lebih cepat tampaknya 3 x lebih lambat dalam pengujian ini
string.format membutuhkan waktu 4,6 detik dan ketika menggunakan '+' dibutuhkan 1,6 detik.
sumber
"1" + "2" + "3" + "4" + "5" + "6" + "7" + "8" + "9" + "10"
sebagai satu string literal, sehingga baris secara efektif menjadi"12345678910" + i
yang lebih cepat dari sebelumnyastring.Format(...)
string.Format mungkin merupakan pilihan yang lebih baik saat template format ("C {0}") disimpan dalam file konfigurasi (seperti Web.config / App.config)
sumber
Saya melakukan sedikit pembuatan profil dari berbagai metode string termasuk string.Format, StringBuilder dan penggabungan string. Rangkaian string hampir selalu mengungguli metode lain dalam membangun string. Jadi, jika kinerja adalah kuncinya, maka itu lebih baik. Namun, jika kinerja tidak kritis maka saya pribadi mencari string.Format agar lebih mudah diikuti dalam kode. (Tapi itu alasan subjektif) Bagaimanapun, StringBuilder mungkin paling efisien sehubungan dengan pemanfaatan memori.
sumber
Saya lebih suka String.Format terkait dengan kinerja
sumber
Penggabungan string membutuhkan lebih banyak memori dibandingkan dengan String.Format. Jadi cara terbaik untuk menggabungkan string menggunakan String.Format atau System.Text.StringBuilder Object.
Mari kita ambil kasus pertama: "C" + rowIndex.ToString () Mari kita asumsikan rowIndex adalah tipe nilai sehingga metode ToString () harus Box untuk mengubah nilai menjadi String dan kemudian CLR membuat memori untuk string baru dengan kedua nilai disertakan.
Sedangkan string.Format mengharapkan parameter objek dan mengambil rowIndex sebagai objek dan mengubahnya menjadi string internal offcourse akan ada Boxing tetapi itu intrinsik dan juga tidak akan memakan banyak memori seperti pada kasus pertama.
Untuk string pendek tidak terlalu penting kurasa ...
sumber