2011-01-21 11 views
6
A = string.Concat("abc","def") 

B = "abc" + "def" 

A vs Badición de cadenas en C#, ¿cómo lo hace el compilador?

Últimamente he sido confundido por qué muchos dicen que definitivamente A hace un procesamiento mucho más rápido en comparación con B. Sin embargo, la cosa es que simplemente decir porque alguien lo dijo o porque es solo la forma en que es. Supongo que puedo escuchar una explicación mucho mejor desde aquí.

¿Cómo trata el compilador estas cadenas?

¡Gracias!

+2

Con cadenas de este tamaño, no importará –

Respuesta

12

Lo primero que hice cuando me uní al equipo del compilador de C# fue que reescribí el optimizador para concatenaciones de cadenas. Buenos tiempos.

Como ya se indicó, los concats de cadenas constantes se realizan en tiempo de compilación. cuerdas no constantes hacer algunas cosas de lujo:

a + b --> String.Concat(a, b) 
a + b + c --> String.Concat(a, b, c) 
a + b + c + d --> String.Concat(a, b, c, d) 
a + b + c + d + e --> String.Concat(new String[] { a, b, c, d, e }) 

Los beneficios de estas optimizaciones son que el método String.Concat puede mirar todos los argumentos, determinar la suma de sus longitudes, y luego hacer una gran cadena que puede mantener todos los resultados.

Aquí hay uno interesante.Suponga que tiene un método M que devuelve una cadena:

s = M() + ""; 

Si M() devuelve un valor nulo, el resultado es la cadena vacía. (null + empty está vacío.) Si M no devuelve null, el resultado no cambia con la concatenación de la cadena vacía. Por lo tanto, esto está realmente optimizado ya que no es una llamada a String.Concat en absoluto. Se convierte en

s = M() ?? "" 

Neat, eh?

5

En C#, el operador adicional para cadenas es solo azúcar sintáctica para String.Concat. Puede verificarlo abriendo el conjunto de salida en el reflector.

Otra cosa a tener en cuenta es que si tiene literales de cadena (o constantes) en su código, como en el ejemplo, el compilador incluso lo cambia a B = "abcdef".

Pero, si usa String.Concat con dos cadenas de literales o constantes, se seguirá llamando a String.Concat, omitiendo la optimización, por lo que la operación + sería más rápida.

lo tanto, para resumir:

stringA + stringB convierte String.Concat(stringA, stringB).
"abc" + "def" convierte "abcdef "
String.Concat("abc", "def") sigue siendo el mismo

algo más que sólo tenía que probar:

En C++/CLI, "abc" + "def" + "ghi" en realidad está traducido a String.Concat(String.Concat("abc", "def"), "ghi")

+3

No con dos literales de cadena, no: 'B' solo se establecerá directamente en" abcdef ". – LukeH

+0

ya se agregó inmediatamente después de la publicación :) – Botz3000

1

En realidad, B se resuelve durante tiempo de compilación. Terminará con B = "abcdef" mientras que para A, la concatenación se pospone hasta el tiempo de ejecución.

+1

Para agregar a esto, el uso de '+' en cadenas cuando * no * confrontado con literales se convertirá en una sola llamada a 'cadena.Concat()' – Joey

5
+1

+1 buena lectura ! gracias – naveen

+0

Solo una nota: creo que muchas personas enfatizan demasiado a StringBuilder. También hay una clase StringWriter en .NET que es mucho más fácil de usar, porque su interfaz pública es muy similar a lo que todos conocen de la clase de la consola. –

+0

Según MSDN, 'StringWriter' es un contenedor alrededor de' StringBuilder'. Por lo tanto, no es vital mencionar 'StringWriter' en el contexto de optimización de código si' StringBuilder' ya se ha discutido. – Brian

1

Si las cadenas son literales, como en su pregunta, entonces la concatenación de las cadenas asignadas a B se llevará a cabo en tiempo de compilación. Su ejemplo se traduce en:

string a = string.Concat("abc", "def"); 
string b = "abcdef"; 

Si las cadenas no son literales, entonces el compilador traduce el operador + en una llamada Concat.

Así que este ...

string x = GetStringFromSomewhere(); 
string y = GetAnotherString(); 

string a = string.Concat(x, y); 
string b = x + y; 

... son trasladados a esta en tiempo de compilación:

string x = GetStringFromSomewhere(); 
string y = GetAnotherString(); 

string a = string.Concat(x, y); 
string b = string.Concat(x, y); 
1

En este caso particular, los dos son en realidad idénticos. El compilador transformará la segunda variante, la que utiliza el operador +, en una llamada a Concat, la primera variante.

Bueno, eso es, si los dos realmente contenían variables de cadena que se concatenaron.

este código:

B = "abc" + "def"; 

transforma realmente en esto, sin concatenación en absoluto:

B = "abcdef"; 

Esto se puede hacer porque el resultado de la suma se puede calcular en tiempo de compilación, por lo el compilador hace esto

Sin embargo, si tuviera que usar algo como esto:

A = String.Concat(stringVariable1, stringVariable2); 
B = stringVariable1 + stringVariable2; 

Entonces los dos va a generar el mismo código.

Sin embargo, me gustaría saber exactamente lo que esos "muchos" dijeron, ya que creo que es algo diferente.

Lo que creo que dijeron es que la concatenación de cadenas es mala, y debería usar StringBuilder o similar.

Por ejemplo, si usted hace esto:

String s = "test"; 
for (int index = 1; index <= 10000; index++) 
    s = s + "test"; 

Entonces lo que sucede es que para cada iteración a través del bucle, construirá una nueva cadena, y dejar que el viejo sea elegible para la recolección de basura.

Además, cada cadena nueva tendrá todos los contenidos de la antigua copiada en ella, lo que significa que moverá una gran cantidad de memoria.

Mientras que el código siguiente:

StringBuilder sb = new StringBuilder("test"); 
for (int index = 1; index <= 10000; index++) 
    sb.Append("test"); 

en su lugar utilizará un buffer interno, que es más grande que lo que es necesario, en caso de que es necesario añadir más texto en él. Cuando ese búfer se llene, se asignará uno nuevo que sea más grande y el anterior se deje para la recolección de basura.

Por lo tanto, en términos de uso de memoria y uso de CPU, la última variante es mucho mejor.

Aparte de eso, trataría de evitar enfocarme demasiado en "es la variante de código X mejor que Y", más allá de lo que ya tiene experiencia. Por ejemplo, uso StringBuilder ahora solo porque soy consciente del caso, pero eso no quiere decir que todo el código que escribo que lo use realmente lo necesite.

Trate de evitar perder tiempo micro-optimizando su código, hasta que sepa que tiene un cuello de botella. En ese momento, el consejo habitual sobre la medida primero, corte posterior, sigue vigente.

Cuestiones relacionadas