Tengo un pequeño fragmento de código que analiza un valor de índice para determinar una entrada de celda en Excel. Me tiene pensando ...
Cuál es la diferencia entre
xlsSheet.Write("C" + rowIndex.ToString(), null, title);
y
xlsSheet.Write(string.Format("C{0}", rowIndex), null, title);
¿Es uno mejor que el otro? ¿Y por qué?
Respuestas:
Antes de C # 6
Para ser honesto, creo que la primera versión es más simple, aunque la simplificaría a:
Sospecho que otras respuestas pueden hablar sobre el impacto en el rendimiento, pero para ser honesto, será mínimo si está presente , y esta versión de concatenación no necesita analizar la cadena de formato.
Las cadenas de formato son excelentes para fines de localización, etc., pero en un caso como este, la concatenación es más simple y funciona igual de bien.
Con C # 6
La interpolación de cadenas facilita la lectura de muchas cosas en C # 6. En este caso, su segundo código se convierte en:
que es probablemente la mejor opción, en mi opinión.
fuente
xlsSheet.Write($"C{rowIndex}", null, title);
Mi preferencia inicial (proveniente de un fondo de C ++) fue String.Format. Dejé esto más tarde debido a las siguientes razones:
- La concatenación de cadenas permite valores nulos,String.Format
pero no. Escribir "s1 + null + s2
" no se rompe, solo trata el valor nulo como String.Empty. Bueno, esto puede depender de su escenario específico: hay casos en los que le gustaría un error en lugar de ignorar silenciosamente un Nombre nulo. Sin embargo, incluso en esta situación, personalmente prefiero verificar si hay nulos y lanzar errores específicos en lugar de la ArgumentNullException estándar que obtengo de String.Format.La idea es que el compilador .NET es lo suficientemente inteligente como para convertir este fragmento de código:
a esto:
Lo que sucede bajo el capó de String.Concat es fácil de adivinar (use Reflector). Los objetos de la matriz se convierten en su cadena mediante ToString (). Luego se calcula la longitud total y solo se asigna una cadena (con la longitud total). Finalmente, cada cadena se copia en la cadena resultante a través de wstrcpy en algún fragmento de código inseguro.
¿Razones
String.Concat
es mucho más rápido? Bueno, todos podemos echar un vistazo a lo queString.Format
está haciendo: se sorprenderá de la cantidad de código necesario para procesar la cadena de formato. Además de esto (he visto comentarios sobre el consumo de memoria),String.Format
utiliza un StringBuilder internamente. Así es cómo:StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
Entonces, por cada argumento pasado, reserva 8 caracteres. Si el argumento es un valor de un dígito, entonces muy mal, tenemos algo de espacio desperdiciado. Si el argumento es un objeto personalizado que devuelve texto extenso
ToString()
, es posible que incluso se necesite una reasignación (en el peor de los casos, por supuesto).Comparado con esto, la concatenación solo desperdicia el espacio de la matriz de objetos (no demasiado, teniendo en cuenta que es una matriz de referencias). No hay análisis para especificadores de formato ni StringBuilder intermediario. La sobrecarga de boxeo / unboxing está presente en ambos métodos.
La única razón por la que optaría por String.Format es cuando se trata de la localización. Poner cadenas de formato en los recursos le permite admitir diferentes idiomas sin alterar el código (piense en situaciones en las que los valores formateados cambian de orden según el idioma, es decir, "después de {0} horas y {1} minutos" puede verse bastante diferente en japonés: ).
Para resumir mi primera publicación (y bastante larga):
ToString()
llamadaToString()
llamadas tú mismo para evitar el boxeo (estoy algo sesgado hacia la legibilidad), igual que la primera opción en tu pregunta.String.Format()
tiene una ventaja.fuente
string.Format
es "seguro" cuando se usa ReSharper; es decir, es tan seguro como cualquier otro código que se pueda utilizar [incorrectamente]. 2)string.Format
no permitirá un "seguro"null
:string.Format("A{0}B", (string)null)
los resultados en "AB". 3) Rara vez me preocupo por este nivel de rendimiento (y con ese fin, es un día raro cuando me retiroStringBuilder
) ...string s = "This " + MyMethod(arg) + " is a test";
se compila en unaString.Concat()
llamada en modo Release.Creo que la primera opción es más legible y esa debería ser su principal preocupación.
string.Format usa un StringBuilder debajo del capó (verifique con el reflector ) por lo que no tendrá ningún beneficio de rendimiento a menos que esté haciendo una cantidad significativa de concatenación. Será más lento para su escenario, pero la realidad es que esta decisión de optimización del micro rendimiento es inapropiada la mayor parte del tiempo y realmente debería centrarse en la legibilidad de su código a menos que esté en un bucle.
De cualquier manera, escriba primero para mejorar la legibilidad y luego use un generador de perfiles de rendimiento para identificar sus puntos de acceso si realmente cree que tiene problemas de rendimiento.
fuente
Para un caso simple en el que se trata de una simple concatenación única, creo que no vale la pena la complejidad de
string.Format
(y no lo he probado, pero sospecho que para un caso simple como este,string.Format
podría ser un poco más lento, con el formato de análisis de cadenas y todo). Como Jon Skeet, prefiero no llamar explícitamente.ToString()
, ya que lastring.Concat(string, object)
sobrecarga lo hará implícitamente , y creo que el código tiene un aspecto más limpio y es más fácil de leer sin él.Pero para más de unas pocas concatenaciones (cuántas son subjetivas), definitivamente prefiero
string.Format
. En cierto punto, creo que tanto la legibilidad como el rendimiento sufren innecesariamente con la concatenación.Si hay muchos parámetros en la cadena de formato (nuevamente, "muchos" es subjetivo), generalmente prefiero incluir índices comentados en los argumentos de reemplazo, para que no pierda la pista de qué valor va a qué parámetro. Un ejemplo artificial:
Actualizar
Se me ocurre que el ejemplo que he dado es un poco confuso, porque parece que he usado tanto la concatenación como
string.Format
aquí. Y sí, lógica y léxicamente, eso es lo que he hecho. Pero todas las concatenaciones serán optimizadas por el compilador 1 , ya que todas son cadenas literales. Entonces, en tiempo de ejecución, habrá una sola cadena. Así que supongo que debería decir que prefiero evitar muchas concatenaciones en tiempo de ejecución .Por supuesto, la mayor parte de este tema está desactualizado ahora, a menos que todavía esté atascado con C # 5 o anterior. Ahora tenemos cadenas interpoladas , que en términos de legibilidad, son muy superiores a
string.Format
, en casi todos los casos. En estos días, a menos que solo esté concatenando un valor directamente al principio o al final de un literal de cadena, casi siempre uso la interpolación de cadenas. Hoy, escribiría mi ejemplo anterior así:De esta manera, pierde la concatenación en tiempo de compilación. El
string.Format
compilador convierte cada cadena interpolada en una llamada a , y sus resultados se concatenan en tiempo de ejecución. Eso significa que esto es un sacrificio del rendimiento en tiempo de ejecución para mejorar la legibilidad. La mayoría de las veces, es un sacrificio que vale la pena, porque la penalización en tiempo de ejecución es insignificante. En el código de rendimiento crítico, sin embargo, es posible que deba perfilar diferentes soluciones.1 Puede ver esto en la especificación de C # :
También puedes verificarlo con un pequeño código:
fuente
String.Format()
Si su cadena fuera más compleja con muchas variables concatenadas, entonces elegiría la cadena.Formato (). Pero para el tamaño de la cadena y la cantidad de variables que se concatenan en su caso, iría con su primera versión, es más espartana .
fuente
He echado un vistazo a String.Format (usando Reflector) y en realidad crea un StringBuilder y luego llama AppendFormat en él. Por lo que es más rápido que concat para múltiples agitaciones. Lo más rápido (creo) sería crear un StringBuilder y hacer las llamadas a Append manualmente. Por supuesto, el número de "muchos" es incierto. Usaría + (en realidad, porque soy un programador de VB principalmente) para algo tan simple como tu ejemplo. A medida que se vuelve más complejo, uso String.Format. Si hay MUCHAS variables, optaría por un StringBuilder y Append, por ejemplo, tenemos código que crea código, allí uso una línea de código real para generar una línea de código generado.
Parece haber cierta especulación sobre cuántas cadenas se crean para cada una de estas operaciones, así que tomemos algunos ejemplos simples.
"C" ya es una cadena.
rowIndex.ToString () crea otra cadena. (@manohard - no ocurrirá ningún boxing de rowIndex)
Luego obtenemos la cadena final.
Si tomamos el ejemplo de
entonces tenemos "C {0}" como una cadena
rowIndex se encajona para pasar a la función
Se crea un nuevo generador de
cadenas Se llama a AppendFormat en el generador de cadenas - No conozco los detalles de cómo funciona AppendFormat, pero supongamos que es ultra eficiente, todavía tendrá que convertir el rowIndex en caja en una cadena.
Luego, convierta el constructor de cadenas en una nueva cadena.
Sé que StringBuilders intenta evitar que se realicen copias de memoria sin sentido, pero String.Format aún termina con una sobrecarga adicional en comparación con la concatenación simple.
Si ahora tomamos un ejemplo con algunas cadenas más
tenemos 6 cadenas para empezar, que serán las mismas para todos los casos.
Usando la concatenación también tenemos 4 cadenas intermedias más el resultado final. Son esos resultados intermedios los que se eliminan mediante el uso de String, Format (o un StringBuilder).
Recuerde que para crear cada cadena intermedia, la anterior debe copiarse en una nueva ubicación de memoria, no es solo la asignación de memoria la que es potencialmente lenta.
fuente
Me gusta String.Format porque puede hacer que su texto formateado sea mucho más fácil de seguir y leer que la concatenación en línea, también es mucho más flexible y le permite formatear sus parámetros, sin embargo, para usos cortos como el suyo, no veo ningún problema en la concatenación.
Para concatenaciones dentro de bucles o en cadenas grandes, siempre debe intentar usar la clase StringBuilder.
fuente
Ese ejemplo probablemente sea demasiado trivial para notar una diferencia. De hecho, creo que en la mayoría de los casos el compilador puede optimizar cualquier diferencia.
Sin embargo, si tuviera que adivinar, daría
string.Format()
una ventaja para escenarios más complicados. Pero eso es más un presentimiento de que es probable que haga un mejor trabajo utilizando un búfer en lugar de producir múltiples cadenas inmutables, y no basadas en datos reales.fuente
Estoy de acuerdo con muchos puntos anteriores, otro punto que creo que debería mencionarse es la capacidad de mantenimiento del código. string.Format permite un cambio de código más fácil.
es decir, tengo un mensaje
"The user is not authorized for location " + location
o"The User is not authorized for location {0}"
si alguna vez quise cambiar el mensaje para decir:
location + " does not allow this User Access"
o"{0} does not allow this User Access"
con string.Format todo lo que tengo que hacer es cambiar la cadena. para la concatenación tengo que modificar ese mensaje
si se usa en varios lugares, puede ahorrar mucho tiempo.
fuente
Tenía la impresión de que string.format era más rápido, parece ser 3 veces más lento en esta prueba
string.format tardó 4.6 segundos y cuando se usa '+' tomó 1.6 segundos.
fuente
"1" + "2" + "3" + "4" + "5" + "6" + "7" + "8" + "9" + "10"
como una cadena literal, por lo que la línea se convierte efectivamente en"12345678910" + i
cuál es más rápida que la anteriorstring.Format(...)
string.Format es probablemente una mejor opción cuando la plantilla de formato ("C {0}") se almacena en un archivo de configuración (como Web.config / App.config)
fuente
Hice un poco de perfilado de varios métodos de cadena, incluidos string.Format, StringBuilder y concatenación de cadenas. La concatenación de cadenas casi siempre superó a los otros métodos de construcción de cadenas. Entonces, si el rendimiento es clave, entonces es mejor. Sin embargo, si el rendimiento no es crítico, personalmente considero que string.Format es más fácil de seguir en el código. (Pero esa es una razón subjetiva) Sin embargo, StringBuilder es probablemente más eficiente con respecto a la utilización de la memoria.
fuente
Prefiero String.Format con respecto al rendimiento
fuente
La concatenación de cadenas requiere más memoria en comparación con String.Format. Entonces, la mejor manera de concatenar cadenas es utilizando String.Format o System.Text.StringBuilder Object.
Tomemos el primer caso: "C" + rowIndex.ToString () Supongamos que rowIndex es un tipo de valor, por lo que el método ToString () tiene que Box para convertir el valor en String y luego CLR crea memoria para la nueva cadena con ambos valores incluidos.
Donde como string.Format espera el parámetro de objeto y toma rowIndex como un objeto y lo convierte en una cadena internamente, por supuesto, habrá Boxing pero es intrínseco y no ocupará tanta memoria como en el primer caso.
Supongo que para cuerdas cortas no importará mucho ...
fuente