C # 'da değişebilen ve değişmeyen bir dize arasındaki fark nedir?


Yanıtlar:


313

Mutable ve immutable, "değişebilir" ve "değiştirilemez" anlamına gelen İngilizce kelimelerdir. Kelimelerin anlamı BT bağlamında aynıdır; yani

  • değiştirilebilir bir dize değiştirilebilir ve
  • değişmez bir dize değiştirilemez.

Bu kelimelerin anlamları diğer programlama dillerinde / ortamlarında olduğu gibi C # / .NET ile aynıdır, ancak türlerin isimleri diğer ayrıntılarda olduğu gibi farklılık gösterebilir.


Kayıt için:

  • String standart C # / .Net değişmez dize türüdür
  • StringBuilder standart C # / .Net değiştirilebilir dize türüdür

C # olarak temsil edilen bir dizede "bir değişiklik yapmak" için String, aslında yeni bir Stringnesne oluşturursunuz. Orijinal Stringdeğiştirilmez ... çünkü değiştirilemez.

Çoğu durumda kullanmak daha iyidir, Stringçünkü onlar hakkında daha kolay bir nedendir; örneğin, başka bir iş parçacığının "dizgimi değiştirebileceğini" düşünebilirsiniz. Ancak, bir işlem dizisi kullanarak bir dize oluşturmanız veya değiştirmeniz gerektiğinde, a kullanmak daha verimli olabilir StringBuilder.


Ve son olarak, StringBuildera'nın değişmez olmadığı için bir dize olmadığını iddia eden insanlar için Microsoft belgeleri şöyle açıklanır StringBuilder:

"Değişken bir karakter dizesini temsil eder . Bu sınıf devralınamaz."


182

String değişmez

yani, dizeler değiştirilemez. Bir dizeyi değiştirdiğinizde (örneğin ekleyerek), aslında yeni bir dize oluşturursunuz.

Ama StringBuilderdeğişmez değil (daha ziyade değişebilir)

Bu nedenle, bir dizeyi birden çok kez birleştirme gibi birçok kez değiştirmeniz gerekiyorsa kullanın StringBuilder.


4
Değişmez dizeleri birçok kez bitirirseniz ne olur? Referansları olmayan dizeler için bellek kullanımı bir sürü? Yoksa sadece yavaş mı?
Rudie

13
@Rudie - her ikisi de. Her birleştirme yeni bir String nesnesi oluşturur ve her iki giriş dizesinin tüm karakterlerini kopyalar. O(N^2)Davranışa yol açar ...
Stephen C

@StephenC anahtar kelimelerle açıkladı.
Kent Liau

6
Eğer bir dize böyle birden concatenations olarak birçok kez, değiştirmek gerekiyorsa, o zaman StringBuilder kullanmak O zihnim ... tamamen sayesinde temizlenir ...
katmanco

45

Bir nesne, oluşturulduktan sonra, üzerinde çeşitli işlemler çağrılarak durumu değiştirilebiliyorsa değiştirilebilir, aksi takdirde değişmezdir.

Değişmez Dize

C # (ve .NET) 'de bir dize System.String sınıfı tarafından temsil edilir. stringAnahtar kelime, bu sınıf için bir diğer adıdır.

System.string sınıfı değişmez, yani bir kez devlet değiştirilemez oluşturulan .

Tüm operasyonlar Yani böyle bir ipe gerçekleştirmek Substring, Remove, Replace, birleştirme kullanarak '+' operatör vb yeni dize oluşturmak ve bunu dönecektir.

Gösteri için aşağıdaki programa bakınız -

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

Bu sırasıyla 'string' ve 'mystring' yazdıracaktır.

İçin değişmezlik yararları ve neden dize değişmez onay olan .NET dize değişmez Neden? .

Değişken Dize

Sık sık değiştirmek istediğiniz bir dizeye sahip olmak istiyorsanız StringBuildersınıfı kullanabilirsiniz . Bir StringBuilder örnek üzerindeki işlemler aynı nesneyi değiştirir .

Daha fazla öneri için ne zaman kullanılacağını StringBuilder ifade StringBuilder ne zaman kullanılır? .


Güzel açıklama!
Hari

36

Tüm stringnesneler C # ile değiştirilemez. Sınıfın nesneleri string, bir kez yaratıldığında, inşa edildiklerinden başka hiçbir değeri temsil edemezler. Bir dizeyi "değiştiriyor" gibi görünen tüm işlemler bunun yerine yeni bir tane oluşturur. Bu bellekle verimsizdir, ancak bir dizenin sizin altında form değiştirmeyeceğine güvenebilme açısından son derece kullanışlıdır - çünkü referansınızı değiştirmediğiniz sürece, atıfta bulunulan dize asla değişmeyecektir.

Değişken bir nesnenin aksine, değiştirilebilecek veri alanları vardır. Bir veya daha fazla yöntemi nesnenin içeriğini değiştirir veya içine yazıldığında nesnenin değerini değiştirecek bir Özelliğe sahiptir.

Değişken bir nesneniz varsa - String'e en çok benzeyen şey StringBuffer- o zaman altından değişmeyeceğinden emin olmak istiyorsanız bir kopyasını oluşturmanız gerekir. Değişken nesnelerin herhangi bir biçiminin Dictionaryveya kümesinin anahtarları olarak kullanılması tehlikelidir, bu nedenle nesnelerin kendileri değişebilir ve veri yapısının bilmenin hiçbir yolu olmaz ve sonuçta programınızı çökertir.

Bununla birlikte, içeriğini değiştirebilirsiniz - bu nedenle, tek bir karakteri veya benzer bir şeyi değiştirmek istediğiniz için tam bir kopya yapmaktan çok, çok daha fazla bellek verimlidir.

Genel olarak, doğru olan şey, bir şey oluştururken değiştirilebilir nesneleri ve işiniz bittiğinde değişmez nesneleri kullanmaktır. Bu elbette değişmez biçimlere sahip nesneler için geçerlidir; koleksiyonların çoğu değil. Bununla birlikte, koleksiyonunuzun dahili durumunu başka bağlamlara gönderirken değişmez olanın eşdeğeri olan salt okunur koleksiyon formları sağlamak genellikle yararlıdır, aksi takdirde bir şey bu dönüş değerini alabilir, bir şeyler yapabilir ve veri.


12

Değişmez:

Bir nesne üzerinde bazı işlemler yaptığınızda, yeni bir nesne oluşturur, bu nedenle durum dize durumunda olduğu gibi değiştirilemez.

değişken

Bir nesne üzerinde bazı işlemler gerçekleştirdiğinizde, nesnenin kendisi, StringBuilder durumunda olduğu gibi yeni bir obje oluşturulmadığını değiştirdi


8

.NET'te System.String (aka string) değişmez bir nesnedir. Bu, bir nesne oluşturduğunuzda daha sonra değerini değiştiremeyeceğiniz anlamına gelir. Yalnızca değişmez bir nesneyi yeniden oluşturabilirsiniz.

System.Text.StringBuilder, System.String öğesinin değiştirilebilir eşdeğeridir ve değerini değiştirebilirsiniz

Örneğin:

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");
    }
}

Aşağıdaki MSIL oluşturur: Kodu araştırırsanız. Bir System.String nesnesini değiştirdiğinizde aslında yeni bir nesne oluşturduğunuzu göreceksiniz. Ancak System.Text.StringBuilder'da metnin değerini her değiştirdiğinizde nesneyi yeniden oluşturmazsınız.

.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

5
Ummm ... bu demonte kod sadece işaretçi atamalarının yapıldığını ve yöntemlerin çağrıldığını gösterir. Değişken ile değişmez arasında neredeyse hiçbir ilgisi yoktur. (Bazı insanlar bazı alakasız örnek kod İnsanlara yardım edecek demonte bu tür şeyleri anlamaya düşünüyorum Beni neden kaçar Başlangıç için, çoğu programcı CLI kodunda akıcı değildir..)
Stephen C

6

.NET sahne arkasında dize havuzu kullandığından dizeler değiştirilebilir. Anlamı :

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

Hem ad hem de ad2, dize havuzundaki aynı bellek konumuna başvuruyor. Şimdi name2'yi şu şekilde değiştirmek istediğinizi varsayalım:

name2 = "My Loving Country";

Dize havuzuna "Sevgi dolu ülkem" için dize havuzuna bakacak, eğer bulursanız, diğer akıllıca yeni dize "Sevgi dolu ülkem" dize havuzunda oluşturulacak ve name2 buna referans alacaktır. Ama bu " Sürecim " sürecinin tamamı değişmedi çünkü isim gibi diğer değişkenler hala kullanıyor. Dize bu yüzden DEMİR DEĞİLDİR .

StringBuilder farklı şekilde çalışır ve string havuzu kullanmaz. Herhangi bir StringBuilder örneği oluşturduğumuzda:

var address  = new StringBuilder(500);

Bu örnek için 500 bayt boyutundaki bellek yığınını ayırır ve tüm işlemler bu bellek konumunu değiştirir ve bu bellek başka bir nesneyle paylaşılmaz. Ve bu nedeni budur StringBuilder olduğunu DEĞİŞKEN .

Umarım yardımcı olur.


5

Aslında yok. String sınıfı değiştirilebilir.

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."
}

Bu tür bir mantık aslında String ve StringBuilder sınıflarında her zaman yapılır. Concat, Substring, vb. Teller kendilerini değiştirmezler, bu yüzden neden "değişmez" olarak kabul edilirler.


Bu arada, bunu dize değişmezleriyle denemeyin , aksi takdirde programınızı kötü bir şekilde karıştırırsınız:

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."

Bunun nedeni, dize değişmezlerinin masaüstü .NET Framework'te stajyer olması; başka bir deyişle, barve bazaynı dizeye noktaya, yani bir başka dönüşecek mutasyona. Bu, dize stajyerliği olmayan WinRT gibi yönetilmeyen bir platform kullanıyorsanız, hepsi iyi ve züppe.


1
İyi evet. Eğer kapalı olması gereken açık soyutlamaları kırarak kuralları ihlal ederseniz, neredeyse hiçbir şey değişmez değildir. Kötü yansıma kullanarak Java'da benzer şeyler yapabilirsiniz ... ancak JLS, aldığınız davranışın tanımsız olduğunu belirtir.
Stephen C

2

Açıklığa kavuşturmak için C # (veya genel olarak .NET) değişken bir dize diye bir şey yoktur. Diğer diller değiştirilebilir değişken dizeleri (değişebilen dize) destekler ancak .NET çerçevesi desteklemez.

Yani sorunuzun doğru cevabı ALL dizesi C # ile değiştirilemez.

string'in belirli bir anlamı vardır. "string" lowercase anahtar sözcüğü, System.String sınıfından başlatılan bir nesne için yalnızca bir kısayoldur. String sınıfından oluşturulan tüm nesneler HER ZAMAN değiştirilemez.

Değişken bir metin temsili istiyorsanız StringBuilder gibi başka bir sınıf kullanmanız gerekir. StringBuilder, yinelenen bir şekilde 'kelimeler' koleksiyonu oluşturmanıza ve daha sonra bunu bir dizeye dönüştürmenize olanak tanır (bir kez daha değişmez).


Üzgünüz, ancak Microsoft belgeleri StringBuilderbununla çelişiyor: bkz. Msdn.microsoft.com/en-us/library/…
Stephen C

1

Veri değeri değiştirilemez. Not: Değişken değeri değiştirilebilir, ancak orijinal değiştirilemez veri değeri atıldı ve bellekte yeni bir veri değeri oluşturuldu.


1

uygulama ayrıntısında.

CLR2'nin System.String değişebilir. StringBuilder.Append çağrılıyor String.AppendInplace (özel yöntem)

CLR4'ün System.String değişmez. StringBuilder parçalama ile Char dizisi var.


0

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

Kısa Cevap: String değişmezken, StringBuilder değiştirilebilir.

Bu ne anlama geliyor ? Wiki diyor ki: Nesneye yönelik olarak, değişmez bir nesne, durumu oluşturulduktan sonra değiştirilemeyen bir nesnedir. Bu, oluşturulduktan sonra değiştirilebilen değiştirilebilir bir nesnenin aksine.

StringBuilder Class belgelerinden:

String nesnesi değiştirilemez. System.String sınıfındaki yöntemlerden birini her kullandığınızda, bellekte yeni bir dize nesnesi oluşturursunuz; bu, yeni nesne için yeni bir alan ayırmayı gerektirir.

Bir dizede tekrarlanan değişiklikler yapmanız gereken durumlarda, yeni bir String nesnesi oluşturmayla ilişkili ek yük maliyetli olabilir.

System.Text.StringBuilder sınıfı, yeni bir nesne oluşturmadan bir dizeyi değiştirmek istediğinizde kullanılabilir. Örneğin, StringBuilder sınıfını kullanmak, bir dizede birçok dizeyi birleştirirken performansı artırabilir.


0

Immective string ve Mutable string builder örneği

        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();

Çıktıyı da sağlayabilirseniz çok güzel olacak @Gokul :)
Roy Lee

Alt dize, temel değeri değiştirmez. Yalnızca bir değer döndürür.
Kye

@Kye ve neden? çünkü dizeleri değişmez :)
LuckyLikey

2 satır kodunuz -: s.Substring (0, 5); Console.WriteLine (s); Burada s.substring () değişmez s. bu örnek, dizenin değişmez olup olmadığını göstermez.
Dhananjay

0

C # dizesi değişmez. Herhangi bir dize ile birleştirirseniz, aslında yeni bir dize yapıyorsunuz, bu yeni dize nesnesi! Ancak StringBuilder değiştirilebilir dize oluşturur.


0

StringBuilder çok büyük bir veri dizesini birleştirmek için daha iyi bir seçenektir çünkü StringBuilder değiştirilebilir bir dize türüdür ve StringBuilder nesnesi değişmez bir türdür, yani StringBuilder dizeyi bitirirken asla yeni bir nesne örneği oluşturmaz.

Birleştirme için ulaşmak için StringBuilder yerine string kullanırsak, her seferinde bellekte yeni bir örnek oluşturur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.