Apa perbedaan antara string yang dapat berubah dan tidak berubah dalam C #?

Jawaban:

313

Mutable dan immutable adalah kata-kata bahasa Inggris yang berarti "bisa berubah" dan "tidak bisa berubah". Arti kata-katanya sama dalam konteks IT; yaitu

  • string yang dapat berubah dapat diubah, dan
  • string yang tidak dapat diubah tidak dapat diubah.

Arti dari kata-kata ini adalah sama dalam C # / .NET seperti pada bahasa pemrograman lain / lingkungan, meskipun (jelas) nama-nama jenis mungkin berbeda, seperti detail lainnya.


Untuk catatan:

  • String adalah tipe string default C # / .Net
  • StringBuilder adalah tipe string C # / .Net yang dapat diubah

Untuk "efek perubahan" pada string yang direpresentasikan sebagai C # String, Anda benar-benar membuat Stringobjek baru . Dokumen asli Stringtidak diubah ... karena tidak dapat diubah.

Dalam kebanyakan kasus lebih baik digunakan Stringkarena lebih mudah alasannya; mis. Anda tidak perlu mempertimbangkan kemungkinan bahwa beberapa utas lainnya mungkin "mengubah string saya". Namun, ketika Anda perlu membuat atau memodifikasi string menggunakan urutan operasi, mungkin lebih efisien untuk menggunakan a StringBuilder.


Dan akhirnya, bagi orang-orang yang menyatakan bahwa a StringBuilderbukan string karena tidak dapat diubah, dokumentasi Microsoft menjelaskan sebagai StringBuilderberikut:

"Merupakan string karakter yang bisa berubah . Kelas ini tidak dapat diwarisi."

Stephen C
sumber
182

String tidak kekal

yaitu string tidak dapat diubah. Ketika Anda mengubah string (dengan menambahkannya misalnya), Anda sebenarnya membuat string baru.

Tetapi StringBuildertidak kekal (melainkan bisa berubah)

jadi jika Anda harus mengubah string berkali-kali, seperti beberapa penggabungan, kemudian gunakan StringBuilder.

Pankaj Agarwal
sumber
4
Apa yang terjadi jika Anda menyanyikan senar abadi berkali-kali? Banyak penggunaan memori untuk string tanpa referensi? Atau lambat?
Rudie
13
@Rudie - keduanya. Setiap rangkaian membuat objek String baru, dan menyalin semua karakter dari kedua string input. Mengarah ke O(N^2)perilaku ...
Stephen C
@StephenC menjelaskan dengan kata kunci.
Kent Liau
6
jika Anda harus mengubah string berkali-kali, seperti beberapa penggabungan, kemudian gunakan StringBuilder ... Itu menjernihkan pikiran saya sepenuhnya terima kasih ...
katmanco
45

Suatu objek bisa berubah jika, begitu dibuat, keadaannya dapat diubah dengan memanggil berbagai operasi di atasnya, jika tidak maka tidak dapat diubah.

String yang Tidak Berubah

Dalam C # (dan .NET) string diwakili oleh kelas System.String. Kata stringkunci adalah alias untuk kelas ini.

Kelas System.String tidak dapat diubah, yaitu sekali dibuat kondisinya tidak dapat diubah .

Jadi semua operasi Anda lakukan pada string seperti Substring, Remove, Replace, Rangkaian menggunakan operator + 'dll akan membuat string baru dan mengembalikannya.

Lihat program berikut untuk demonstrasi -

string str = "mystring";
string newString = str.Substring(2);
Console.WriteLine(newString);
Console.WriteLine(str);

Ini akan mencetak 'string' dan 'mystring' masing-masing.

Untuk manfaat keabadian dan mengapa string tidak dapat diubah periksa Mengapa .NET String tidak dapat diubah? .

String yang bisa berubah

Jika Anda ingin memiliki string yang ingin Anda modifikasi sering Anda bisa menggunakan StringBuilderkelas. Operasi pada StringBuilder instance akan memodifikasi objek yang sama .

Untuk saran lebih lanjut tentang kapan menggunakan StringBuilder merujuk ke Kapan menggunakan StringBuilder? .

Lepaskan Kondolikar
sumber
Penjelasan yang indah!
Hari
36

Semua stringobjek tidak berubah dalam C #. Objek kelas string, sekali dibuat, tidak akan pernah bisa mewakili nilai apa pun selain yang dibangun dengan mereka. Semua operasi yang tampaknya "mengubah" sebuah string malah menghasilkan yang baru. Ini tidak efisien dengan memori, tetapi sangat berguna untuk dapat percaya bahwa string tidak akan berubah bentuk di bawah Anda - karena selama Anda tidak mengubah referensi Anda, string yang dirujuk tidak akan pernah berubah.

Objek yang bisa berubah, sebaliknya, memiliki bidang data yang dapat diubah. Satu atau lebih metode akan mengubah konten objek, atau memiliki Properti yang, ketika ditulis ke dalam, akan mengubah nilai objek.

Jika Anda memiliki objek yang dapat diubah - yang paling mirip dengan String adalah StringBuffer- maka Anda harus membuat salinannya jika Anda ingin benar-benar yakin itu tidak akan berubah dari bawah Anda. Inilah sebabnya mengapa objek yang dapat diubah berbahaya untuk digunakan sebagai kunci ke dalam bentuk Dictionaryatau set apa pun - objek itu sendiri dapat berubah, dan struktur data tidak memiliki cara untuk mengetahui, yang mengarah ke data yang korup yang pada akhirnya akan membuat crash program Anda.

Namun, Anda dapat mengubah isinya- jadi itu, jauh lebih efisien memori daripada membuat salinan lengkap karena Anda ingin mengubah satu karakter, atau sesuatu yang serupa.

Secara umum, hal yang benar untuk dilakukan adalah menggunakan objek yang bisa berubah saat Anda membuat sesuatu, dan objek yang tidak dapat diubah begitu Anda selesai. Ini berlaku untuk objek yang memiliki bentuk tidak berubah, tentu saja; sebagian besar koleksi tidak. Seringkali berguna untuk menyediakan bentuk-bentuk koleksi read-only, meskipun, yang setara dengan kekal, ketika mengirimkan keadaan internal koleksi Anda ke konteks lain- jika tidak, sesuatu dapat mengambil nilai pengembalian, melakukan sesuatu untuk itu, dan merusak Anda data.

Adam Norberg
sumber
12

Abadi

Ketika Anda melakukan beberapa operasi pada objek, itu menciptakan objek baru sehingga keadaan tidak dapat dimodifikasi seperti dalam kasus string.

Yg mungkin berubah

Ketika Anda melakukan beberapa operasi pada suatu objek, objek itu sendiri memodifikasi tidak ada objek baru yang dibuat dalam kasus StringBuilder

TalentTuner
sumber
8

Dalam .NET System.String (alias string) adalah objek yang tidak berubah. Itu berarti ketika Anda membuat objek Anda tidak dapat mengubah nilainya setelah itu. Anda hanya dapat membuat ulang objek yang tidak dapat diubah.

System.Text.StringBuilder adalah bisa berubah setara dengan System.String dan Anda dapat memotong nilainya

Sebagai contoh:

class Program
{
    static void Main(string[] args)
    {

        System.String str = "inital value";
        str = "\nsecond value";
        str = "\nthird value";

        StringBuilder sb = new StringBuilder();
        sb.Append("initial value");
        sb.AppendLine("second value");
        sb.AppendLine("third value");
    }
}

Hasilkan MSIL berikut: Jika Anda menyelidiki kode. Anda akan melihat bahwa setiap kali Anda memotong objek dari System.String Anda benar-benar membuat yang baru. Tetapi dalam System.Text.StringBuilder setiap kali Anda mengubah nilai teks Anda tidak membuat ulang objek.

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       62 (0x3e)
  .maxstack  2
  .locals init ([0] string str,
           [1] class [mscorlib]System.Text.StringBuilder sb)
  IL_0000:  nop
  IL_0001:  ldstr      "inital value"
  IL_0006:  stloc.0
  IL_0007:  ldstr      "\nsecond value"
  IL_000c:  stloc.0
  IL_000d:  ldstr      "\nthird value"
  IL_0012:  stloc.0
  IL_0013:  newobj     instance void [mscorlib]System.Text.StringBuilder::.ctor()
  IL_0018:  stloc.1
  IL_0019:  ldloc.1
  IL_001a:  ldstr      "initial value"
  IL_001f:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
  IL_0024:  pop
  IL_0025:  ldloc.1
  IL_0026:  ldstr      "second value"
  IL_002b:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::AppendLine(string)
  IL_0030:  pop
  IL_0031:  ldloc.1
  IL_0032:  ldstr      "third value"
  IL_0037:  callvirt   instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::AppendLine(string)
  IL_003c:  pop
  IL_003d:  ret
} // end of method Program::Main
cahit beyaz
sumber
5
Ummm ... bahwa kode yang dibongkar hanya menunjukkan bahwa penunjuk penunjuk sedang dibuat dan metode sedang dipanggil. Ini (hampir) tidak ada hubungannya dengan bisa berubah versus tidak berubah. (Ini lolos dari saya mengapa beberapa orang berpikir bahwa membongkar beberapa contoh kode yang tidak relevan akan membantu orang memahami hal semacam ini. Sebagai permulaan, sebagian besar programmer tidak fasih dalam kode CLI.)
Stephen C
6

String bisa berubah karena .NET menggunakan string pool di belakang layar. Itu berarti :

string name = "My Country";
string name2 = "My Country";

Nama dan name2 merujuk ke lokasi memori yang sama dari kumpulan string. Sekarang anggaplah Anda ingin mengubah name2 menjadi:

name2 = "My Loving Country";

Ini akan mencari string pool untuk string "My Loving Country", jika ditemukan Anda akan mendapatkan referensi itu string baru yang bijak lainnya "My Loving Country" akan dibuat di string pool dan name2 akan mendapatkan referensi itu. Tetapi seluruh proses " My Country " ini tidak berubah karena variabel lain seperti nama masih menggunakannya. Dan itulah alasan mengapa string IMMUTABLE .

StringBuilder bekerja dengan cara yang berbeda dan tidak menggunakan string pool. Saat kami membuat instance dari StringBuilder:

var address  = new StringBuilder(500);

Ini mengalokasikan potongan memori ukuran 500 byte untuk contoh ini dan semua operasi hanya mengubah lokasi memori ini dan memori ini tidak dibagi dengan objek lain. Dan itu adalah alasan mengapa StringBuilder adalah bisa berubah .

Saya harap ini akan membantu.

Rahul Garg
sumber
5

Sebenarnya tidak ada. Kelas String bisa berubah.

unsafe
{
    string foo = string.Copy("I am immutable.");
    fixed (char* pChar = foo)
    {
        char* pFoo = pChar;

        pFoo[5] = ' ';
        pFoo[6] = ' ';
    }

    Console.WriteLine(foo); // "I am   mutable."
}

Logika semacam ini dilakukan sepanjang waktu di kelas String dan StringBuilder. Mereka hanya mengalokasikan string baru setiap kali Anda memanggil Concat, Substring, dll. Dan menggunakan aritmatika pointer untuk menyalin ke string baru. String tidak bermutasi, karenanya mengapa mereka dianggap "tidak berubah".


Omong-omong, jangan coba - coba ini dengan string literal atau Anda akan mengacaukan program Anda:

string bar = "I am a string.";

fixed (char* pChar = bar)
{
    char* pBar = pChar;

    pBar[2] = ' ';
}

string baz = "I am a string.";

Console.WriteLine(baz); // "I  m a string."

Ini karena string literal diinternir di desktop .NET Framework; dengan kata lain, bardan bazarahkan ke string yang sama persis, sehingga bermutasi satu akan bermutasi yang lain. Ini semua bagus dan bagus jika Anda menggunakan platform yang tidak dikelola seperti WinRT, yang tidak memiliki string interning.

James Ko
sumber
1
Baiklah. Jika Anda melanggar aturan dengan memecahkan abstraksi terbuka yang seharusnya ditutup, maka hampir tidak ada yang berubah. Anda dapat melakukan hal-hal analog di Jawa menggunakan refleksi jahat ... tetapi JLS menyatakan bahwa perilaku yang Anda dapatkan tidak terdefinisi.
Stephen C
2

Untuk memperjelas tidak ada yang namanya string yang bisa berubah di C # (atau .NET secara umum). Bahasa lainnya mendukung string yang dapat diubah (string yang dapat berubah) tetapi .NET framework tidak.

Jadi jawaban yang benar untuk pertanyaan Anda adalah SEMUA string tidak dapat diubah dalam C #.

string memiliki arti tertentu. kata kunci "string" huruf kecil hanyalah pintasan untuk objek yang dibuat dari kelas System.String. Semua objek yang dibuat dari kelas string SELALU tidak dapat diubah.

Jika Anda ingin representasi teks yang dapat diubah maka Anda perlu menggunakan kelas lain seperti StringBuilder. StringBuilder memungkinkan Anda membangun koleksi 'kata' secara iteratif dan kemudian mengubahnya menjadi string (sekali lagi tidak dapat diubah).

Gerald Davis
sumber
Maaf, tetapi dokumentasi Microsoft untuk StringBuilderkontradiksi ini: lihat msdn.microsoft.com/en-us/library/…
Stephen C
1

Nilai data tidak dapat diubah. Catatan: Nilai variabel dapat diubah, tetapi nilai data tidak berubah asli dibuang dan nilai data baru dibuat dalam memori.

vikas kumar
sumber
1

dalam detail implementasi.

System.String CLR2 bisa berubah. StringBuilder.Append memanggil String.AppendInplace (metode pribadi)

System.String CLR4 tidak dapat diubah. StringBuilder memiliki array Char dengan chunking.

Kazuk
sumber
0

Dari http://yassershaikh.com/what-is-the-difference-between-strings-and-stringbuilder-in-c-net/

Jawaban Singkat: String tidak dapat diubah - sedangkan StringBuilder bisa berubah.

Apa artinya ? Wiki mengatakan: Dalam berorientasi objek, objek yang tidak dapat diubah adalah objek yang kondisinya tidak dapat diubah setelah dibuat. Ini berbeda dengan objek yang bisa berubah, yang dapat dimodifikasi setelah dibuat.

Dari dokumentasi Kelas StringBuilder:

Objek String tidak dapat diubah. Setiap kali Anda menggunakan salah satu metode di kelas System.String, Anda membuat objek string baru di memori, yang membutuhkan alokasi ruang baru untuk objek baru itu.

Dalam situasi di mana Anda perlu melakukan modifikasi berulang pada string, overhead yang terkait dengan membuat objek String baru bisa mahal.

Kelas System.Text.StringBuilder dapat digunakan ketika Anda ingin memodifikasi string tanpa membuat objek baru. Misalnya, menggunakan kelas StringBuilder dapat meningkatkan kinerja saat menyatukan banyak string dalam satu lingkaran.

Yasser Shaikh
sumber
0

Berikut adalah contoh untuk string Immutable dan Mutable builder

        Console.WriteLine("Mutable String Builder");
        Console.WriteLine("....................................");
        Console.WriteLine();
        StringBuilder sb = new StringBuilder("Very Good Morning");
        Console.WriteLine(sb.ToString());
        sb.Remove(0, 5);
        Console.WriteLine(sb.ToString());

        Console.WriteLine();

        Console.WriteLine("Immutable String");
        Console.WriteLine("....................................");
        Console.WriteLine();
        string s = "Very Good Morning";
        Console.WriteLine(s);
        s.Substring(0, 5);
        Console.WriteLine(s);
        Console.ReadLine();
Gokul
sumber
Akan sangat menyenangkan jika Anda bisa memberikan outputnya juga @Gokul :)
Roy Lee
Substring tidak mengubah nilai yang mendasarinya. Ini hanya mengembalikan nilai.
Kye
@ Ya dan mengapa? karena string tidak berubah :)
LuckyLikey
Kode 2 baris Anda -: s.Substring (0, 5); Console.WriteLine (s); Di sini s.substring () tidak berubah s. contoh ini tidak menunjukkan apakah string tidak dapat diubah.
Dhananjay
0

String dalam C # tidak berubah. Jika Anda menggabungkannya dengan string apa pun, Anda sebenarnya membuat string baru, yaitu objek string baru! Tapi StringBuilder menciptakan string yang bisa berubah.

Md Shahriar
sumber
0

StringBuilder adalah pilihan yang lebih baik untuk menggabungkan string data yang sangat besar karena StringBuilder adalah tipe string yang dapat berubah dan objek StringBuilder adalah tipe yang tidak dapat diubah, yang berarti StringBuilder tidak pernah membuat instance objek baru saat menggabungkan string.

Jika kita menggunakan string alih-alih StringBuilder untuk mencapai concatenation maka itu akan membuat instance baru dalam memori setiap waktu.

Sher Singh
sumber