2012-05-19 16 views
6

Sé que string es inmutable y StringBuilder es mutable. Pero, ¿alguien puede explicar la siguiente salida del código? Dado que ambos son tipos de referencia, ¿por qué tienen diferentes resultados?¿Cuál es la diferencia entre string y StringBuilder?

String s1 = "hello"; 
String s2 = "hello"; 
Console.WriteLine(s1 == s2); //true 
Console.WriteLine(Object.ReferenceEquals(s1, s2)); //true 

StringBuilder sb1 = new StringBuilder("hello"); 
StringBuilder sb2 = new StringBuilder("hello"); 
Console.WriteLine(sb1 == sb2); //false 
Console.WriteLine(Object.ReferenceEquals(sb1, sb2)); //false 
+1

Está comparando dos referencias de objeto 'StringBuilder' diferentes. Son dos objetos separados. – birryree

+0

+1, no solo por una pregunta excelente, sino por preguntarla tan claramente, con una muestra completa de código que se ha comentado perfectamente. –

+1

Esta pregunta en realidad no tiene nada que ver con 'StringBuilder'. Se trata realmente de "¿por qué dos variables de cadena inicializadas con dos literales de cadena que contienen la misma secuencia de caracteres se comparan como si fueran el mismo objeto"? –

Respuesta

10

Desde ambos son tipos de referencia, ¿por qué tienen diferentes resultados?

Porque los objetos string están altamente optimizados. En particular, dado que son inmutables, pueden ser internados por el compilador para evitar la duplicación.

Si tiene dos objetos diferentes string que representan exactamente la misma cadena de caracteres (como en su ejemplo), el compilador reconocerá eso y mantendrá solo una instancia del objeto de cadena real.

El resultado es que los objetos s1 y s2 son en realidad el mismo objeto en lo que respecta al compilador e incluso hacen referencia a la misma ubicación en la memoria.

Esta contabilidad ocurre detrás de escena en algo llamado "mesa de pasante", pero eso no es realmente algo con lo que deba preocuparse. Lo importante es que todos los literales de cadena son internados por defecto por el compilador.

El mismo tipo de cosas no suceden para objetos StringBuilder, porque no son inmutables. Están diseñados para permitirle modificar un objeto de cadena, y como tal, las optimizaciones no tienen mucho sentido. Es por eso que sus objetos sb1 y sb2 se ven en realidad como dos objetos diferentes.

La regla de oro es bastante simple: utilice string de forma predeterminada, o cuando desee una sola cadena de caracteres inmutables. Solo use StringBuilder cuando desee modificar la misma cadena varias veces, por ejemplo, en un bucle u otra sección relativamente corta de código.

lectura relevantes: Optimizing C# String Performance

+0

Eso tiene perfecto sentido. – GLP

1

Cuando usted está haciendo lo siguiente que está comparando dos StringBuilder diferente, no se opone a sus valores:

StringBuilder sb1 = new StringBuilder("hello"); 
StringBuilder sb2 = new StringBuilder("hello"); 
Console.WriteLine(sb1 == sb2); //false 

Así es como se puede comparar sus valores:

Console.WriteLine(sb1.ToString() == sb2.ToString()); 
4

Cuando se declara

String s1 = "hello"; 
String s2 = "hello"; 

el compilador es suficientemente inteligente para saber que las dos cadenas son (y siempre será) idénticos, por lo que almacena "hello" sólo una vez y crea s1 y s2 como alias para la misma memoria física. Más tarde, cuando pruebas la igualdad, los dos son iguales porque son esencialmente la misma variable.

Por otro lado, cuando se declara

StringBuilder sb1 = new StringBuilder("hello"); 
StringBuilder sb2 = new StringBuilder("hello"); 

el compilador crea dos variables (porque ambos son mutables, pero resultan ser inicializado con el mismo valor).Copia la cadena "hello" en cada uno de ellos, pero ahora hay 2 copias, porque cada una de ellas podría cambiarse más tarde. Entonces, aunque sus contenidos son los mismos, son 2 entidades diferentes que residen en diferentes ubicaciones de memoria física, por lo que las pruebas de igualdad de objetos fallan.

2

De forma predeterminada, cuando se comparan dos objetos de tipo referencia, el resultado es verdadero solo si ambas referencias son iguales, lo que significa que ambos operandos deben hacer referencia a la misma instancia de objeto. Debido a que los objetos referenciados por sb1 y sb2 son dos objetos diferentes, el resultado de la comparación de StringBuilders es falso.

Pero la clase String anula el operador de igualdad de tal manera que no compara los objetos por sus referencias, sino por sus valores, ya que este comportamiento es muy intuitivo y esperado por los programadores. Eso explica por qué s1 == s2 devuelve verdadero.

La razón por la cual Object.ReferenceEquals (s1, s2) también devuelve verdadero (aunque parece que s1 y s2 hace referencia a diferentes instancias de cadena) se llama string interning. Hace que CLR coloque todas las apariciones de literales de cadena idénticos (como "hallo" y "hallo" en el ejemplo) en el grupo interno de cadenas solo una vez por aplicación, por lo que tanto s1 como s2 hacen referencia a la misma instancia de cadena "hallo" . Esto es posible porque la cadena es inmutable.

Cuestiones relacionadas