Salida de cadena: ¿formato o concat en C#?


Digamos que desea generar o concat cadenas. ¿Cuál de los siguientes estilos prefieres?

  • var p = new { FirstName = "Bill", LastName = "Gates" };

  • Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

  • Console.WriteLine(p.FirstName + " " + p.LastName);

¿Prefieres usar formato o simplemente concateas cadenas? ¿Cuál es tu favorito? Es uno de estos lastimar tus ojos?

¿Tienes algún argumento racional para usar uno y no el otro?

Yo iría por el segundo.

Author: Philippe, 2008-08-19

30 answers

Pruebe este código.

Es una versión ligeramente modificada de tu código.
1. Quité la consola.WriteLine ya que es probablemente unos pocos órdenes de magnitud más lento de lo que estoy tratando de medir.
2. Estoy iniciando el cronómetro antes del bucle y deteniéndolo justo después, de esta manera no estoy perdiendo precisión si la función toma por ejemplo 26.4 ticks para ejecutarse.
3. La forma en que dividiste el resultado por algunas iteraciones fue incorrecta. Vea lo que sucede si tiene 1000 milisegundos y 100 milisegundo. En ambas situaciones, obtendrá 0 ms después de dividirlo por 1000000.

Stopwatch s = new Stopwatch();

var p = new { FirstName = "Bill", LastName = "Gates" };

int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;

string result;
s.Start();
for (var i = 0; i < n; i++)
    result = (p.FirstName + " " + p.LastName);
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();
s.Start();
for (var i = 0; i < n; i++)
    result = string.Format("{0} {1}", p.FirstName, p.LastName);
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();


Console.Clear();
Console.WriteLine(n.ToString()+" x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Thread.Sleep(4000);

, Esos son mis resultados:

1000000 x result = string.Formato("{0} {1}", p. FirstName, p. LastName); took: 618ms - 2213706 ticks
1000000 x result = (p. FirstName + "" + p. LastName); took: 166ms - 595610 ticks

 86
Author: Michał Piaskowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-01 06:15:41

Me sorprende que tanta gente quiera encontrar inmediatamente el código que se ejecuta más rápido. Si UN MILLÓN DE iteraciones AÚN tardan menos de un segundo en procesarse, ¿esto va a ser de ALGUNA MANERA perceptible para el usuario final? No es muy probable.

Optimización prematura = ERROR.

Iría con la opción String.Format, solo porque tiene más sentido desde un punto de vista arquitectónico. No me importa el rendimiento hasta que se convierte en un problema (y si me pregunto: ¿Necesito concatenar un millón de nombres a la vez? Seguro que no caben todos en la pantalla...)

Considere si su cliente más tarde quiere cambiarlo para que puedan configurar si desea mostrar "Firstname Lastname" o "Lastname, Firstname." Con la opción de formato, esto es fácil: simplemente cambie la cadena de formato. Con el concat, necesitarás código extra. Seguro que no suena como un gran problema en este ejemplo en particular, pero extrapolar.

 153
Author: Fredrik Kalseth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-29 11:55:59

Oh querido - después de leer una de las otras respuestas traté de invertir el orden de las operaciones - por lo que realizar la concatenación primero, a continuación, la Cadena.Formato...

Bill Gates
Console.WriteLine(p.FirstName + " " + p.LastName); took: 8ms - 30488 ticks
Bill Gates
Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took: 0ms - 182 ticks

Así que el orden de las operaciones hace una GRAN diferencia, o más bien la primera operación SIEMPRE es mucho más lenta.

Aquí están los resultados de una ejecución donde las operaciones se completan más de una vez. He intentado cambiar las órdenes, pero las cosas generalmente siguen las mismas reglas, una vez que el primer resultado es ignorado:

Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 5ms - 20335 ticks
Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 0ms - 156 ticks
Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 0ms - 122 ticks
Bill Gates
Console.WriteLine("{0} {1}", FirstName, LastName); took: 0ms - 181 ticks
Bill Gates
Console.WriteLine("{0} {1}", FirstName, LastName); took: 0ms - 122 ticks
Bill Gates
String.Concat(FirstName, " ", LastName); took: 0ms - 142 ticks
Bill Gates
String.Concat(FirstName, " ", LastName); took: 0ms - 117 ticks

Como puede ver, las ejecuciones posteriores del mismo método (refactoricé el código en 3 métodos) son gradualmente más rápidas. El más rápido parece ser la Consola.WriteLine (String.Concat(...)) método, seguido de la concatenación normal, y luego las operaciones formateadas.

El retraso inicial en el inicio es probablemente la inicialización de la secuencia de consola, como la colocación de una consola.Writeline ("Start!") antes de la primera operación pone todos los tiempos de nuevo en línea.

 54
Author: samjudson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-11 13:43:27

Las cadenas son inmutables, esto significa que la misma pequeña pieza de memoria se usa una y otra vez en su código. Agregar las mismas dos cadenas juntas y crear la misma cadena nueva una y otra vez no afecta la memoria. . Net es lo suficientemente inteligente como para usar la misma referencia de memoria. Por lo tanto, su código no prueba realmente la diferencia entre los dos métodos concat.

Pruébate esto para el tamaño:

Stopwatch s = new Stopwatch();

int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0, sbElapsedMilliseconds = 0, sbElapsedTicks = 0;

Random random = new Random(DateTime.Now.Millisecond);

string result;
s.Start();
for (var i = 0; i < n; i++)
    result = (random.Next().ToString() + " " + random.Next().ToString());
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();

s.Start();
for (var i = 0; i < n; i++)
    result = string.Format("{0} {1}", random.Next().ToString(), random.Next().ToString());
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();

StringBuilder sb = new StringBuilder();
s.Start();
for(var i = 0; i < n; i++){
    sb.Clear();
    sb.Append(random.Next().ToString());
    sb.Append(" ");
    sb.Append(random.Next().ToString());
    result = sb.ToString();
}
s.Stop();
sbElapsedMilliseconds = s.ElapsedMilliseconds;
sbElapsedTicks = s.ElapsedTicks;
s.Reset();

Console.WriteLine(n.ToString() + " x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x sb.Clear();sb.Append(random.Next().ToString()); sb.Append(\" \"); sb.Append(random.Next().ToString()); result = sb.ToString(); took: " + (sbElapsedMilliseconds) + "ms - " + (sbElapsedTicks) + " ticks");
Console.WriteLine("****************");
Console.WriteLine("Press Enter to Quit");
Console.ReadLine();

Salida de muestra:

1000000 x result = string.Format("{0} {1}", p.FirstName, p.LastName); took: 513ms - 1499816 ticks
1000000 x result = (p.FirstName + " " + p.LastName); took: 393ms - 1150148 ticks
1000000 x sb.Clear();sb.Append(random.Next().ToString()); sb.Append(" "); sb.Append(random.Next().ToString()); result = sb.ToString(); took: 405ms - 1185816 ticks
 35
Author: MrPhil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-02 20:04:46

Compadezcan a los pobres traductores

Si sabe que su solicitud permanecerá en inglés, entonces está bien, guarde las marcas del reloj. Sin embargo, muchas culturas suelen ver Lastname Firstname en, por ejemplo, direcciones.

Así que use string.Format(), especialmente si alguna vez va a tener su aplicación en cualquier lugar que el inglés no sea el primer idioma.

 23
Author: Jeremy McGee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-30 21:11:53

Aquí están mis resultados sobre 100,000 iteraciones:

Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took (avg): 0ms - 689 ticks
Console.WriteLine(p.FirstName + " " + p.LastName); took (avg): 0ms - 683 ticks

Y aquí está el código del banco:

Stopwatch s = new Stopwatch();

var p = new { FirstName = "Bill", LastName = "Gates" };

//First print to remove the initial cost
Console.WriteLine(p.FirstName + " " + p.LastName);
Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

int n = 100000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;

for (var i = 0; i < n; i++)
{
    s.Start();
    Console.WriteLine(p.FirstName + " " + p.LastName);
    s.Stop();
    cElapsedMilliseconds += s.ElapsedMilliseconds;
    cElapsedTicks += s.ElapsedTicks;
    s.Reset();
    s.Start();
    Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
    s.Stop();
    fElapsedMilliseconds += s.ElapsedMilliseconds;
    fElapsedTicks += s.ElapsedTicks;
    s.Reset();
}

Console.Clear();

Console.WriteLine("Console.WriteLine(\"{0} {1}\", p.FirstName, p.LastName); took (avg): " + (fElapsedMilliseconds / n) + "ms - " + (fElapsedTicks / n) + " ticks");
Console.WriteLine("Console.WriteLine(p.FirstName + \" \" + p.LastName); took (avg): " + (cElapsedMilliseconds / n) + "ms - " + (cElapsedTicks / n) + " ticks");

Entonces, no se de quien es la respuesta a marcar como una respuesta:)

 14
Author: Philippe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-09 12:49:01

Concatenar cadenas está bien en un escenario simple como ese - es más complicado con cualquier cosa más complicada que eso, incluso LastName, FirstName. Con el formato se puede ver, de un vistazo, cuál será la estructura final de la cadena al leer el código, con la concatenación se hace casi imposible discernir inmediatamente el resultado final(excepto con un ejemplo muy simple como este).

Lo que eso significa a largo plazo es que cuando vuelvas a hacer un cambio en el formato de cadena, tendrá la capacidad de aparecer y hacer algunos ajustes en la cadena de formato, o arrugar su frente y comenzar a moverse por todo tipo de accesores de propiedad mezclados con texto, lo que es más probable que presente problemas.

Si estás usando. NET 3.5 puedes usar un método de extensión como este y obtener una sintaxis fácil de usar como esta:

string str = "{0} {1} is my friend. {3}, {2} is my boss.".FormatWith(prop1,prop2,prop3,prop4);

Finalmente, a medida que su aplicación crece en complejidad, puede decidir que para sanely mantener cadenas en su aplicación desea moverlas a un archivo de recursos para localizarlas o simplemente a un helper estático. Esto será mucho más fácil de lograr si ha utilizado constantemente formatos, y su código puede ser simplemente refactorizado para usar algo como

string name = String.Format(ApplicationStrings.General.InformalUserNameFormat,this.FirstName,this.LastName);
 9
Author: Nathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-19 15:56:23

Para una manipulación muy simple usaría la concatenación, pero una vez que se supera el formato de 2 o 3 elementos se vuelve más apropiado IMO.

Otra razón para preferir String.El formato es que las cadenas. NET son inmutables y hacerlo de esta manera crea menos copias temporales/intermedias.

 7
Author: user2189331,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-19 15:50:44

Si bien entiendo totalmente la preferencia de estilo y elegí la concatenación para mi primera respuesta en parte basada en mi propia preferencia, parte de mi decisión se basó en el pensamiento de que la concatenación sería más rápida. Así que, por curiosidad, lo probé y los resultados fueron asombrosos, especialmente para una cuerda tan pequeña.

Usando el siguiente código:

    System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch();

    var p = new { FirstName = "Bill", LastName = "Gates" };

    s.Start();
    Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
    s.Stop();
    Console.WriteLine("Console.WriteLine(\"{0} {1}\", p.FirstName, p.LastName); took: " + s.ElapsedMilliseconds + "ms - " + s.ElapsedTicks + " ticks");

    s.Reset();
    s.Start();
    Console.WriteLine(p.FirstName + " " + p.LastName);
    s.Stop();

    Console.WriteLine("Console.WriteLine(p.FirstName + \" \" + p.LastName); took: " + s.ElapsedMilliseconds + "ms - " + s.ElapsedTicks + " ticks");

Obtuve los siguientes resultados:

Bill Gates
Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took: 2ms - 7280 ticks
Bill Gates
Console.WriteLine(p.FirstName + " " + p.LastName); took: 0ms - 67 ticks

El uso del método de formato es más de 100 veces más lento!! La concatenación no incluso registrarse como 1ms, que es la razón por la que la salida del temporizador garrapatas, así.

 6
Author: Adam Haile,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-19 16:02:27

Para la concatenación básica de cadenas, generalmente uso el segundo estilo, más fácil de leer y más simple. Sin embargo, si estoy haciendo una combinación de cadena más complicada, generalmente opto por Cadena.Formato.

Cadena.El formato ahorra muchas cotizaciones y ventajas...

Console.WriteLine("User {0} accessed {1} on {2}.", user.Name, fileName, timestamp);
vs
Console.WriteLine("User " + user.Name + " accessed " + fileName + " on " + timestamp + ".");

Solo unos pocos caracteres guardados, pero creo que, en este ejemplo, el formato lo hace mucho más limpio.

 5
Author: Mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-19 15:55:01

Una mejor prueba sería vigilar su memoria usando Perfmon y los contadores de memoria CLR. Mi entendimiento es que toda la razón por la que desea utilizar Cadena.Formatear en lugar de solo concatenar cadenas es, ya que las cadenas son inmutables, está sobrecargando innecesariamente al recolector de basura con cadenas temporales que deben reclamarse en la próxima pasada.

StringBuilder y String.El formato, aunque potencialmente más lento, es más eficiente en memoria.

¿Qué tiene de malo ¿concatenación de cadenas?

 5
Author: David Hill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-22 14:27:23

Generalmente prefiero lo primero, ya que especialmente cuando las cadenas se alargan puede ser mucho más fácil de leer.

El otro beneficio es creo que uno de rendimiento, ya que este último en realidad realiza 2 sentencias de creación de cadenas antes de pasar la cadena final a la Consola.Método de escritura. Cadena.Format utiliza un StringBuilder bajo las portadas, creo, por lo que se evitan múltiples concatenaciones.

Debe tenerse en cuenta sin embargo que si los parámetros que está pasando a la cadena.Formato (y otros métodos como la consola.Write) son tipos de valor, luego se encajonarán antes de pasarlos, lo que puede proporcionar sus propias visitas de rendimiento. Blog post sobre esto aquí.

 5
Author: samjudson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-09-01 11:31:12

A partir de C# 6.0 se pueden usar cadenas interpoladas para hacer esto, lo que simplifica aún más el formato.

var name = "Bill";
var surname = "Gates";
MessageBox.Show($"Welcome to the show, {name} {surname}!");

Una expresión de cadena interpolada se parece a una cadena de plantilla que contiene expresiones. Una expresión de cadena interpolada crea una cadena reemplazando las expresiones contenidas con las representaciones toString de los resultados de las expresiones.

Las cadenas interpoladas tienen un rendimiento similar al de las cadenas.Formato, pero legibilidad mejorada y sintaxis más corta, debido al hecho de que los valores y expresiones se insertan en línea.

Por favor, consulte también este artículo de dotnetperls sobre la interpolación de cadenas.

Si está buscando una forma predeterminada de formatear sus cadenas, esto tiene sentido en términos de legibilidad y rendimiento (excepto si los microsegundos van a hacer una diferencia en su caso de uso específico).

 5
Author: Saragis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-26 18:07:13
  1. El formateo es la forma". NET" de hacerlo. Ciertas herramientas de refactorización (Refactor! por un lado) incluso propondrá refactorizar el código de estilo concat para usar el estilo de formato.
  2. el Formato es más fácil de optimizar para el compilador (aunque el segundo probablemente ser refactorizado para usar la "Concat" método rápido).
  3. El formato suele ser más claro de leer (especialmente con el formato "elegante").
  4. Formateo significa llamadas implícitas a '.toString ' en todas las variables, lo cual es bueno para la legibilidad.
  5. De acuerdo con "Effective C#", las implementaciones de.NET 'WriteLine' y 'Format' están en mal estado, autoboxean todos los tipos de valor (lo cual es malo). "C# efectivo "aconseja realizar".toString ' llamadas explícitamente, que en mi humilde opinión es falso (ver Jeff posting)
  6. Por el momento, las sugerencias de tipo de formato no son verificadas por el compilador, lo que resulta en errores de tiempo de ejecución. Sin embargo, esto podría modificarse en futuras versiones.
 4
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-19 15:59:21

Elijo basado en la legibilidad. Prefiero la opción de formato cuando hay algo de texto alrededor de las variables. En este ejemplo:

Console.WriteLine("User {0} accessed {1} on {2}.", 
                   user.Name, fileName, timestamp);

Entiendes el significado incluso sin nombres de variables, mientras que el concat está lleno de comillas y signos + y confunde mis ojos:

Console.WriteLine("User " + user.Name + " accessed " + fileName + 
                  " on " + timestamp + ".");

(Tomé prestado el ejemplo de Mike porque me gusta)

Si la cadena de formato no significa mucho sin nombres de variables, tengo que usar concat:

   Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

La opción de formato me hace leer el nombres de variables y asignarlos a los números correspondientes. La opción concat no requiere eso. Todavía estoy confundido por las comillas y los signos+, pero la alternativa es peor. ¿Ruby?

   Console.WriteLine(p.FirstName + " " + p.LastName);

En cuanto al rendimiento, espero que la opción de formato sea más lenta que el concat, ya que format requiere que la cadena se analice . No recuerdo haber tenido que optimizar este tipo de instrucción, pero si lo hiciera, miraría string métodos como Concat() y Join().

La otra ventaja con el formato es que la cadena de formato se puede poner en un archivo de configuración. Muy útil con mensajes de error y texto de interfaz de usuario.

 4
Author: DonkeyMaster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-13 08:35:59

Si tiene la intención de localizar el resultado, entonces String.El formato es esencial porque es posible que los diferentes lenguajes naturales ni siquiera tengan los datos en el mismo orden.

 4
Author: Christian Hayter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-07 14:50:08

Usaría la cadena.Formato, pero también tendría la cadena de formato en los archivos fuente para que pueda ser localizado para otros idiomas. Usar una cadena simple concat no te permite hacer eso. Obviamente, si alguna vez no necesitas localizar esa cadena, esta no es una razón para pensar. Realmente depende de para qué sirve la cadena.

Si se va a mostrar al usuario, usaría String.Formato para que pueda localizar si lo necesito-y FxCop lo revisará por mí, solo en caso :)

Si contiene números o cualquier otra cosa que no sea cadena (por ejemplo, fechas), usaría Cadena.Formato porque me da más control sobre el formato.

Si es para construir una consulta como SQL, usaría Linq.

Si para concatenar cadenas dentro de un bucle, usaría StringBuilder para evitar problemas de rendimiento.

Si es para alguna salida que el usuario no verá, y no va a afectar el rendimiento, usaría String.Formato porque estoy en el hábito de usarlo de todos modos y estoy acostumbrado a él:)

 4
Author: Wilka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-07 19:27:14

Dentro de una semana el 19 de agosto de 2015, esta pregunta tendrá exactamente siete (7) años. Ahora hay una mejor manera de hacerlo. Mejor en términos de mantenibilidad, ya que no he hecho ninguna prueba de rendimiento en comparación con solo concatenar cadenas (pero ¿importa en estos días? ¿unos pocos milisegundos de diferencia?). La nueva forma de hacerlo con C# 6.0:

var p = new { FirstName = "Bill", LastName = "Gates" };
var fullname = $"{p.FirstName} {p.LastName}";

Esta nueva característica es mejor , IMO, y en realidad mejor en nuestro caso ya que tenemos códigos donde construir querystrings cuyos valores dependen de algunos factores. Imagine una querystring donde tenemos 6 argumentos. Así que en lugar de hacer a, por ejemplo:

var qs = string.Format("q1={0}&q2={1}&q3={2}&q4={3}&q5={4}&q6={5}", 
    someVar, anotherVarWithLongName, var3, var4, var5, var6)

En se puede escribir así y es más fácil de leer:

var qs=$"q1={someVar}&q2={anotherVarWithLongName}&q3={var3}&q4={var4}&q5={var5}&q6={var6}";
 4
Author: von v.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-12 03:18:07

Si estás tratando con algo que necesita ser fácil de leer (y esto es la mayoría del código), me quedaría con la versión de sobrecarga del operador A MENOS que:

  • El código necesita ser ejecutado millones de veces
  • Estás haciendo toneladas de concats (más de 4 es una tonelada)
  • El código está dirigido hacia el Marco Compacto

Bajo al menos dos de estas circunstancias, usaría StringBuilder en su lugar.

 3
Author: plinth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-22 14:43:54

Creo que esto depende en gran medida de lo compleja que sea la salida. Tiendo a elegir cualquier escenario que funcione mejor en ese momento.

Elija la herramienta correcta en función del trabajo :D ¡Lo que se vea más limpio!

 2
Author: mercutio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-19 15:50:34

Prefiero el segundo también, pero no tengo argumentos racionales en este momento para apoyar esa posición.

 2
Author: Chuck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-19 15:51:26

Buena!

Acaba de añadir

        s.Start();
        for (var i = 0; i < n; i++)
            result = string.Concat(p.FirstName, " ", p.LastName);
        s.Stop();
        ceElapsedMilliseconds = s.ElapsedMilliseconds;
        ceElapsedTicks = s.ElapsedTicks;
        s.Reset();

Y es aún más rápido (supongo que string.Concat se llama en ambos ejemplos, pero el primero requiere algún tipo de traducción).

1000000 x result = string.Format("{0} {1}", p.FirstName, p.LastName); took: 249ms - 3571621 ticks
1000000 x result = (p.FirstName + " " + p.LastName); took: 65ms - 944948 ticks
1000000 x result = string.Concat(p.FirstName, " ", p.LastName); took: 54ms - 780524 ticks
 2
Author: Philippe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-20 18:07:42

Dado que no creo que las respuestas aquí cubran todo, me gustaría hacer una pequeña adición aquí.

Console.WriteLine(string format, params object[] pars) llamadas string.Format. El ' + ' implica concatenación de cadenas. No creo que esto siempre tenga que ver con el estilo; tiendo a mezclar los dos estilos dependiendo del contexto en el que me encuentre.

Respuesta Corta

La decisión a la que te enfrentas tiene que ver con la asignación de cadenas. Trataré de hacerlo simple.

Di que tienes{[19]]}

string s = a + "foo" + b;

Si ejecuta esto, lo hará evalúe como sigue:

string tmp1 = a;
string tmp2 = "foo" 
string tmp3 = concat(tmp1, tmp2);
string tmp4 = b;
string s = concat(tmp3, tmp4);

tmp aquí no es realmente una variable local, pero es temporal para el JIT (se empuja en la pila IL). Si empuja una cadena en la pila (como ldstr en IL para literales), pone una referencia a un puntero de cadena en la pila.

En el momento en que llame a concat esta referencia se convierte en un problema, porque no hay ninguna referencia de cadena disponible que contenga ambas cadenas. Esto significa que. NET necesita asignar un nuevo bloque de memoria, y luego rellénalo con las dos cuerdas. La razón por la que esto es un problema, es porque la asignación es relativamente costosa.

Que cambia la pregunta a: ¿Cómo se puede reducir el número de concat operaciones?

Entonces, la respuesta aproximada es: string.Format para >1 concat, '+' funcionará bien para 1 concat. Y si no le importa hacer optimizaciones de micro rendimiento, string.Format funcionará bien en el caso general.

Una nota sobre la Cultura

Y luego hay algo llamado cultura...

string.Format le permite usar CultureInfo en su formato. Un simple operador ' + ' utiliza la cultura actual.

Este es un comentario especialmente importante si está escribiendo formatos de archivo y, por ejemplo. double valores que 'agrega' a una cadena. En diferentes máquinas, puede terminar con cadenas diferentes si no usa string.Format con un CultureInfo explícito.

F. ex. considere lo que sucede si cambia a '.'por a', ' mientras escribes tu archivo de valores separados por comas... en holandés, el separador decimal es una coma, por lo que su usuario podría obtener una sorpresa 'divertida'.

Respuesta más detallada

Si no conoce el tamaño exacto de la cadena de antemano, es mejor usar una política como esta para sobreasignar los búferes que usa. El espacio de holgura se llena primero, después de lo cual se copian los datos.

Crecer significa asignar un nuevo bloque de memoria y copiar los datos antiguos al nuevo búfer. Antiguo el bloque de memoria puede entonces ser liberado. Usted obtiene la línea de fondo en este punto: el cultivo es una operación costosa.

La forma más práctica de hacer esto es usar una política de sobreasignación. La política más común es sobreasignar colchones en las potencias de 2. Por supuesto, tienes que hacerlo un poco más inteligente que eso (ya que no tiene sentido crecer desde 1,2,4,8 si ya sabes que necesitas 128 caracteres), pero te haces una idea. La póliza asegura que no necesita muchas de las costosas operaciones I descrito anteriormente.

StringBuilder es una clase que básicamente sobrealocaliza el búfer subyacente en potencias de dos. string.Format usa StringBuilder debajo del capó.

Esto hace que su decisión sea una compensación básica entre asignar y anexar (- múltiple) (w/w.o. culture) o simplemente asignar y anexar.

 2
Author: atlaste,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-22 09:19:03

Personalmente, el segundo, ya que todo lo que está utilizando está en el orden directo en el que se emitirá. Mientras que con el primero tienes que hacer coincidir el {0} y {1} con el var adecuado, que es fácil de estropear.

Al menos no es tan malo como el sprintf de C++ donde si obtienes el tipo de variable incorrecto, todo explotará.

Además, dado que el segundo está todo en línea y no tiene que hacer ninguna búsqueda y reemplazo para todas las {0} cosas, este último debe ser más rápido... aunque no estoy seguro.

 1
Author: Adam Haile,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-19 15:49:57

En realidad me gusta el primero porque cuando hay muchas variables entremezcladas con el texto me parece más fácil de leer. Además, es más fácil tratar con comillas cuando se usa la cadena.Format (), uh, format. Aquí está un análisis decente de la concatenación de cadenas.

 1
Author: adparadox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-19 15:57:20

Siempre he ido a la cadena.Format () ruta. Poder almacenar formatos en variables como el ejemplo de Nathan es una gran ventaja. En algunos casos puedo añadir una variable, pero una vez más de 1 variable se está concatenado I refactorizar para utilizar el formato.

 1
Author: Scott Muc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-19 19:16:49

Oh, y solo para completar, lo siguiente es un par de garrapatas más rápido que la concatenación normal:

Console.WriteLine(String.Concat(p.FirstName," ",p.LastName));
 1
Author: samjudson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-20 08:38:11

El primero (formato) me parece mejor. Es más legible y no está creando objetos de cadena temporales adicionales.

 1
Author: Rismo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-23 19:55:24

Tenía curiosidad por saber dónde estaba StringBuilder con estas pruebas. Resultados a continuación...

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

      var p = new { FirstName = "Bill", LastName = "Gates" };

      var tests = new[] {
         new { Name = "Concat", Action = new Action(delegate() { string x = p.FirstName + " " + p.LastName; }) },
         new { Name = "Format", Action = new Action(delegate() { string x = string.Format("{0} {1}", p.FirstName, p.LastName); }) },
         new { Name = "StringBuilder", Action = new Action(delegate() {
            StringBuilder sb = new StringBuilder();
            sb.Append(p.FirstName);
            sb.Append(" ");
            sb.Append(p.LastName);
            string x = sb.ToString();
         }) }
      };

      var Watch = new Stopwatch();
      foreach (var t in tests) {
         for (int i = 0; i < 5; i++) {
            Watch.Reset();
            long Elapsed = ElapsedTicks(t.Action, Watch, 10000);
            Console.WriteLine(string.Format("{0}: {1} ticks", t.Name, Elapsed.ToString()));
         }
      }
   }

   public static long ElapsedTicks(Action ActionDelg, Stopwatch Watch, int Iterations) {
      Watch.Start();
      for (int i = 0; i < Iterations; i++) {
         ActionDelg();
      }
      Watch.Stop();
      return Watch.ElapsedTicks / Iterations;
   }
}

Resultados:

Concat: 406 ticks
Concat: 356 ticks
Concat: 411 ticks
Concat: 299 ticks
Concat: 266 ticks
Format: 5269 ticks
Format: 954 ticks
Format: 1004 ticks
Format: 984 ticks
Format: 974 ticks
StringBuilder: 629 ticks
StringBuilder: 484 ticks
StringBuilder: 482 ticks
StringBuilder: 508 ticks
StringBuilder: 504 ticks
 1
Author: spoulson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-22 15:07:50

De acuerdo con el material de MCSD prep, Microsoft sugiere usar el operador + cuando se trata de un número muy pequeño de concatenaciones (probablemente de 2 a 4). Todavía no estoy seguro de por qué, pero es algo a considerar.

 1
Author: Babak Naffas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-04 20:31:04