简体   繁体   English

C# 中可变字符串和不可变字符串有什么区别?

[英]What is the difference between a mutable and immutable string in C#?

C# 中可变字符串和不可变字符串有什么区别?

Mutable and immutable are English words meaning "can change" and "cannot change" respectively. Mutable 和 immutable 分别是英文单词,意思是“可以改变”和“不能改变”。 The meaning of the words is the same in the IT context;这些词的含义在 IT 上下文中是相同的; ie IE

  • a mutable string can be changed, and可以更改可变字符串,并且
  • an immutable string cannot be changed.不可更改的字符串不能更改。

The meanings of these words are the same in C# / .NET as in other programming languages / environments, though (obviously) the names of the types may differ, as may other details.这些词在 C#/.NET 中的含义与在其他编程语言/环境中相同,尽管(显然)类型的名称可能不同,其他细节也可能不同。


For the record:作为记录:

  • String is the standard C# / .Net immutable string type String是标准的 C#/.Net 不可变字符串类型
  • StringBuilder is the standard C# / .Net mutable string type StringBuilder是标准的 C#/.Net 可变字符串类型

To "effect a change" on a string represented as a C# String , you actually create a new String object.要对表示为 C# String的字符串“进行更改”,您实际上要创建一个新的String对象。 The original String is not changed ... because it is unchangeable.原始String没有改变……因为它是不可改变的。

In most cases it is better to use String because it is easier reason about them;在大多数情况下,最好使用String因为它更容易理解; eg you don't need to consider the possibility that some other thread might "change my string".例如,您无需考虑其他线程可能“更改我的字符串”的可能性。

However, when you need to construct or modify a string using a sequence of operations, it may be more efficient to use a StringBuilder .但是,当您需要使用一系列操作构造或修改字符串时,使用StringBuilder可能更有效。 An example is when you are concatenating many string fragments to form a large string:一个例子是当您连接许多字符串片段以形成一个大字符串时:

  • If you do this as a sequence of String concatenations, you copy O(N^2) characters, where N is the number of component strings.如果您将其作为一系列String连接来执行,则您将复制O(N^2)字符,其中N是组件字符串的数量。
  • If use a StringBuilder you only copy O(N) characters.如果使用StringBuilder您只能复制O(N)字符。

And finally, for those people who assert that a StringBuilder is not a string because it is not immutable, the Microsoft documentation describes StringBuilder thus:最后,对于那些断言StringBuilder不是字符串因为它不是不可变的人,Microsoft 文档这样描述StringBuilder

"Represents a mutable string of characters. This class cannot be inherited." “代表一个可变的字符串。这个类不能被继承。”

String is immutable String是不可变的

ie strings cannot be altered.即字符串不能改变。 When you alter a string (by adding to it for example), you are actually creating a new string.当您更改一个字符串(例如通过添加)时,您实际上是在创建一个新字符串。

But StringBuilder is not immutable (rather, it is mutable)但是StringBuilder不是一成不变的(相反,它是可变的)

so if you have to alter a string many times, such as multiple concatenations, then use StringBuilder .因此,如果您必须多次更改字符串,例如多次连接,请使用StringBuilder

An object is mutable if, once created, its state can be changed by calling various operations on it, otherwise it is immutable.一个对象是可变的,如果一旦创建,它的状态可以通过调用它的各种操作来改变,否则它是不可变的。

Immutable String不可变字符串

In C# (and .NET) a string is represented by class System.String.在 C#(和 .NET)中,字符串由 System.String 类表示。 The string keyword is an alias for this class. string关键字是此类的别名。

The System.String class is immutable, ie once created its state cannot be altered . System.String 类是不可变的,即一旦创建它的状态就不能改变

So all the operations you perform on a string like Substring , Remove , Replace , concatenation using '+' operator etc will create a new string and return it.因此,您对字符串(如SubstringRemoveReplace 、使用 '+' 运算符的连接等)执行的所有操作都将创建一个新字符串并返回它。

See the following program for demonstration -请参阅以下程序进行演示 -

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

This will print 'string' and 'mystring' respectively.这将分别打印 'string' 和 'mystring'。

For the benefits of immutability and why string are immutable check Why .NET String is immutable?对于不变性好处以及为什么字符串是不可变的检查为什么 .NET 字符串是不可变的? . .

Mutable String可变字符串

If you want to have a string which you want to modify often you can use the StringBuilder class.如果您想要一个经常修改的字符串,您可以使用StringBuilder类。 Operations on a StringBuilder instance will modify the same object .StringBuilder实例的操作将修改同一个对象

For more advice on when to use StringBuilder refer to When to use StringBuilder?有关何时使用StringBuilder更多建议,请参阅何时使用 StringBuilder? . .

All string objects are immutable in C#.所有string对象在 C# 中都是不可变的。 Objects of the class string , once created, can never represent any value other than the one they were constructed with.string对象一旦创建,就永远不能表示除了它们被构造的值之外的任何值。 All operations that seem to "change" a string instead produce a new one.所有似乎“改变”字符串的操作都会产生一个新的字符串。 This is inefficient with memory, but extremely useful with regard to being able to trust that a string won't change out form under you- because as long as you don't change your reference, the string being referred to will never change.这对于内存来说是低效的,但是对于能够相信字符串不会在您的情况下改变形式非常有用 - 因为只要您不更改您的引用,被引用的字符串就永远不会改变。

A mutable object, by contrast, has data fields that can be altered.相比之下,可变对象具有可以更改的数据字段。 One or more of its methods will change the contents of the object, or it has a Property that, when written into, will change the value of the object.它的一个或多个方法会改变对象的内容,或者它有一个属性,当写入时,会改变对象的值。

If you have a mutable object- the most similar one to String is StringBuffer - then you have to make a copy of it if you want to be absolutely sure it won't change out from under you.如果您有一个可变对象(与 String 最相似的对象是StringBuffer ,那么如果您想绝对确保它不会从您身下改变,您必须制作它的副本。 This is why mutable objects are dangerous to use as keys into any form of Dictionary or set- the objects themselves could change, and the data structure would have no way of knowing, leading to corrupt data that would, eventually, crash your program.这就是为什么将可变对象用作任何形式的Dictionary或 set 的键是危险的 - 对象本身可能会改变,而数据结构将无法知道,导致数据损坏,最终导致程序崩溃。

However, you can change its contents- so it's much, much more memory efficient than making a complete copy because you wanted to change a single character, or something similar.但是,您可以更改其内容 - 因此它比制作完整副本的内存效率要高得多,因为您想更改单个字符或类似的东西。

Generally, the right thing to do is use mutable objects while you're creating something, and immutable objects once you're done.通常,正确的做法是在创建时使用可变对象,完成后使用不可变对象。 This applies to objects that have immutable forms, of course;当然,这适用于具有不可变形式的对象; most of the collections don't.大多数集合都没有。 It's often useful to provide read-only forms of collections, though, which is the equivalent of immutable, when sending the internal state of your collection to other contexts- otherwise, something could take that return value, do something to it, and corrupt your data.但是,在将集合的内部状态发送到其他上下文时,提供只读形式的集合通常很有用,这相当于不可变的 - 否则,某些东西可能会获取该返回值,对其进行某些操作并破坏您的数据。

Immutable :不可变的:

When you do some operation on a object, it creates a new object hence state is not modifiable as in case of string.当您对对象执行某些操作时,它会创建一个新对象,因此状态不可修改,就像字符串一样。

Mutable可变的

When you perform some operation on a object, object itself modified no new obect created as in case of StringBuilder当您对对象执行某些操作时,对象本身不会像 StringBuilder 那样修改新对象

In .NET System.String (aka string) is a immutable object.在 .NET System.String(又名字符串)中是一个不可变对象。 That means when you create an object you can not change it's value afterwards.这意味着当您创建一个对象时,您之后无法更改它的值。 You can only recreate a immutable object.您只能重新创建一个不可变对象。

System.Text.StringBuilder is mutable equivalent of System.String and you can chane its value System.Text.StringBuilder 是 System.String 的可变等价物,您可以更改其值

For Example:例如:

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

Generates following MSIL : If you investigate the code.生成以下 MSIL:如果您调查代码。 You will see that whenever you chane an object of System.String you are actually creating new one.您将看到,每当您更改 System.String 对象时,您实际上是在创建新对象。 But in System.Text.StringBuilder whenever you change the value of text you dont recreate the object.但是在 System.Text.StringBuilder 中,无论何时更改文本值,都不会重新创建对象。

.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

Strings are mutable because .NET use string pool behind the scene.字符串是可变的,因为 .NET 在幕后使用字符串池。 It means :它的意思是 :

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

Both name and name2 are referring to same memory location from string pool. name 和 name2 都指的是字符串池中的相同内存位置。 Now suppose you want to change name2 to :现在假设您想将 name2 更改为:

name2 = "My Loving Country";

It will look in to string pool for the string "My Loving Country", if found you will get the reference of it other wise new string "My Loving Country" will be created in string pool and name2 will get reference of it.它将在字符串池中查找字符串“My Loving Country”,如果找到,您将获得它的引用,否则将在字符串池中创建新字符串“My Loving Country”,name2 将获得它的引用。 But it this whole process " My Country " was not changed because other variable like name is still using it.但是整个过程“我的国家”没有改变,因为其他变量如name仍在使用它。 And that is the reason why string are IMMUTABLE .这就是 string 是IMMUTABLE的原因。

StringBuilder works in different manner and don't use string pool. StringBuilder以不同的方式工作并且不使用字符串池。 When we create any instance of StringBuilder :当我们创建 StringBuilder 的任何实例时:

var address  = new StringBuilder(500);

It allocate memory chunk of size 500 bytes for this instance and all operation just modify this memory location and this memory not shared with any other object.它为此实例分配大小为 500 字节的内存块,所有操作只修改此内存位置,并且此内存不与任何其他对象共享。 And that is the reason why StringBuilder is MUTABLE .这就是StringBuilderMUTABLE的原因。

I hope it will help.我希望它会有所帮助。

None, actually.没有,实际上。 The String class is mutable. String 类是可变的。

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

This kind of logic is done all the time in the String and StringBuilder classes, actually.实际上,这种逻辑一直在 String 和 StringBuilder 类中完成。 They just allocate a new string each time you call Concat, Substring, etc. and use pointer arithmetic to copy over to the new string.每次调用 Concat、Substring 等时,它们只是分配一个新字符串,并使用指针算法复制到新字符串。 Strings just don't mutate themselves, hence why they are considered "immutable".字符串本身不会发生变异,因此它们被认为是“不可变的”。


By the way, do not attempt this with string literals or you will badly mess up your program:顺便说一句,不要用字符串文字尝试,或者你将严重搞乱你的程序:

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

This is because string literals are interned in the desktop .NET Framework;这是因为字符串字面量在桌面 .NET Framework 中; in other words, bar and baz point to the exact same string, so mutating one will mutate the other.换句话说, barbaz指向完全相同的字符串,因此改变一个将改变另一个。 This is all fine and dandy though if you're using an unmanaged platform like WinRT, which lacks string interning.不过,如果您使用的是像 WinRT 这样缺乏字符串实习的非托管平台,这一切都很好。

The data value may not be changed.数据值不得更改。 Note: The variable value may be changed, but the original immutable data value was discarded and a new data value was created in memory.注意:变量值可能会改变,但原始的不可变数据值被丢弃,并在内存中创建了一个新的数据值。

in implementation detail.在实施细节上。

CLR2's System.String is mutable. CLR2 的 System.String 是可变的。 StringBuilder.Append calling String.AppendInplace (private method) StringBuilder.Append 调用 String.AppendInplace(私有方法)

CLR4's System.String is immutable. CLR4 的 System.String 是不可变的。 StringBuilder have Char array with chunking. StringBuilder 具有带分块的 Char 数组。

To clarify there is no such thing as a mutable string in C# (or .NET in general).澄清一下,在 C#(或一般的 .NET)中没有可变字符串之类的东西。 Other langues support mutable strings (string which can change) but the .NET framework does not.其他语言支持可变字符串(可以更改的字符串),但 .NET 框架不支持。

So the correct answer to your question is ALL string are immutable in C#.所以你的问题的正确答案是所有字符串在 C# 中都是不可变的。

string has a specific meaning.字符串有特定的含义。 "string" lowercase keyword is merely a shortcut for an object instantiated from System.String class. “string”小写关键字只是从 System.String 类实例化的对象的快捷方式。 All objects created from string class are ALWAYS immutable.从字符串类创建的所有对象始终是不可变的。

If you want a mutable representation of text then you need to use another class like StringBuilder.如果您想要文本的可变表示,那么您需要使用另一个类,如 StringBuilder。 StringBuilder allows you to iteratively build a collection of 'words' and then convert that to a string (once again immutable). StringBuilder 允许您迭代地构建“单词”的集合,然后将其转换为字符串(再次不可变)。

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

Short Answer : String is immutable – whereas StringBuilder is mutable.简短回答:String 是不可变的——而 StringBuilder 是可变的。

What does that mean ?这意味着什么 ? Wiki says : In object-oriented, an immutable object is an object whose state cannot be modified after it is created.维基说:在面向对象中,不可变对象是指在创建后状态无法修改的对象。 This is in contrast to a mutable object, which can be modified after it is created.这与可变对象形成对比,可变对象可以在创建后进行修改。

From the StringBuilder Class documentation:从 StringBuilder 类文档:

The String object is immutable. String 对象是不可变的。 Every time you use one of the methods in the System.String class, you create a new string object in memory, which requires a new allocation of space for that new object.每次使用 System.String 类中的方法之一时,都会在内存中创建一个新的字符串对象,这需要为该新对象分配新的空间。

In situations where you need to perform repeated modifications to a string, the overhead associated with creating a new String object can be costly.在需要对字符串执行重复修改的情况下,与创建新 String 对象相关的开销可能会很昂贵。

The System.Text.StringBuilder class can be used when you want to modify a string without creating a new object.当您想要修改字符串而不创建新对象时,可以使用 System.Text.StringBuilder 类。 For example, using the StringBuilder class can boost performance when concatenating many strings together in a loop.例如,在循环中将多个字符串连接在一起时,使用 StringBuilder 类可以提高性能。

Here is the example for Immutable string and Mutable string 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();

String in C# is immutable. C# 中的字符串是不可变的。 If you concatenate it with any string, you are actually making a new string, that is new string object !如果将它与任何字符串连接起来,实际上是在创建一个新字符串,即新字符串对象! But StringBuilder creates mutable string.但是 StringBuilder 创建了可变字符串。

StringBuilder is a better option to concat a huge data string because the StringBuilder is a mutable string type and StringBuilder object is an immutable type, that means StringBuilder never create a new instance of object while concat the string. StringBuilder 是连接巨大数据字符串的更好选择,因为 StringBuilder 是可变字符串类型,而 StringBuilder 对象是不可变类型,这意味着 StringBuilder 在连接字符串时永远不会创建对象的新实例。

If we are using string instead of StringBuilder to achieve for concatenation then it will create new instance in memory every time.如果我们使用 string 而不是 StringBuilder 来实现连接,那么它每次都会在内存中创建新实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM