Pregunta

Mi pregunta es la siguiente: es la concatenación de cadenas en C # segura? Si la concatenación de cadenas conduce a errores inesperados, y sustituye a la concatenación de cadenas utilizando StringBuilder hace que esos errores a desaparecer, lo que podría indicar que?

Antecedentes: Estoy desarrollando una pequeña línea de comandos para aplicaciones C #. Se necesita argumentos de línea de comando, realiza una consulta SQL poco complicado, y produce alrededor de 1300 filas de datos en un archivo con formato XML.

Mi programa inicial siempre se ejecuta bien en modo de depuración. Sin embargo, en modo de lanzamiento sería llegar a por el resultado de SQL 750, y luego morir con un error. El error fue que una determinada columna de datos no se puede leer, incluso a través del método Read () del objeto SqlDataReader acababa de regresar verdadera.

Este problema se resolvió mediante el uso de StringBuilder para todas las operaciones en el código, donde antes no había sido "cadena1 + cadena2". No estoy hablando de la concatenación de cadenas dentro del bucle de consulta SQL, donde StringBuilder ya estaba en uso. Estoy hablando de concatenaciones simples entre dos o tres variables de cadena corta anteriores en el código.

Me dio la impresión de que C # fue lo suficientemente inteligente como para manejar la gestión de memoria para la adición de unas cadenas juntas. ¿Me equivoco? O indica esto algún otro tipo de problema de código?

¿Fue útil?

Solución

Además de lo que estás haciendo es probablemente el mejor hecho con las API XML en lugar de cadenas o StringBuilder me cabe duda de que el error que se ve es debido a la concatenación de cadenas. Tal vez el cambio a StringBuilder simplemente enmascarado el error o se fue por arriba con gracia, pero dudo que el uso de cadenas en realidad fue la causa.

Otros consejos

Para responder a su pregunta: contatenation cadena en C # (y .NET en general) es "seguro", pero hacerlo en un bucle estrecho que usted describe es probable que cause presión severa de la memoria y poner la tensión en el recolector de basura.

Me arriesgaría a decir que los errores de los que habla estaban relacionados con el agotamiento de recursos de algún tipo, pero sería útil si se pudiera proporcionar más detalles - por ejemplo, ¿recibió una excepción? ¿La aplicación termina anormalmente?

Antecedentes: .NET cadenas son inmutables, por lo que cuando se hace una concatenación de esta manera:

var stringList = new List<string> {"aaa", "bbb", "ccc", "ddd", //... };
string result = String.Empty;
foreach (var s in stringList)
{
    result = result + s;
}

Esto es aproximadamente equivalente a lo siguiente:

string result = "";
result = "aaa"
string temp1 = result + "bbb";
result = temp1;
string temp2 = temp1 + "ccc";
result = temp2;
string temp3 = temp2 + "ddd";
result = temp3;
// ...
result = tempN + x;

El propósito de este ejemplo es hacer hincapié en que cada vez los resultados de bucle en la asignación de una nueva cadena temporal.

Dado que las cadenas son inmutables, el tiempo de ejecución no tiene opciones alternativas, pero para asignar una nueva cadena cada vez que se agrega otra cadena al final de su resultado.

A pesar de que la cadena result se actualiza constantemente para que apunte a la última y mejor resultado intermedio, que se está produciendo una gran cantidad de estos cadena temporal sin nombre que se convierten en elegibles para la recolección de basura casi inmediatamente.

Al final de esta concatenación tendrá las siguientes cadenas almacenadas en la memoria (suponiendo, para simplificar, que el recolector de basura no se ha ejecutado).

string a = "aaa";
string b = "bbb";
string c = "ccc";
// ...
string temp1 = "aaabbb";
string temp2 = "aaabbbccc";
string temp3 = "aaabbbcccddd";
string temp4 = "aaabbbcccdddeee";
string temp5 = "aaabbbcccdddeeefff";
string temp6 = "aaabbbcccdddeeefffggg";
// ...

A pesar de todas estas variables temporales implícitos son aptos para reciclaje casi inmediatamente, que todavía tienen que ser asignados. Al realizar la concatenación en un bucle estrecho esto se va a poner un montón de tensión en el colector de basura y, si no otra cosa, hará que su código funciona muy lentamente. He visto el impacto en el rendimiento de esta primera parte, y se convierte en verdaderamente dramática como su cadena concatenada se hace más grande.

Lo que se recomienda es utilizar siempre una StringBuilder si se está haciendo más que unas pocas concatenaciones de cadenas. StringBuilder utiliza una memoria intermedia mutable para reducir el número de asignaciones que son necesarios en la construcción de su cadena.

concatenación de cadenas es seguro, aunque más memoria que el uso de un StringBuilder si contatenating un gran número de cadenas en un bucle. Y en casos extremos se podría estar quedándose sin memoria.

Es casi seguro que un error en el código.

Tal vez usted está contatenating un gran número de cadenas. O tal vez es otra cosa completamente diferente.

Me gustaría volver a la depuración y sin ninguna idea preconcebida de la causa raíz - si usted todavía tiene problemas tratar de reducir al mínimo necesario para repro el código de problema y post

.

¿Cuánto tiempo se tarda la versión concatenación vs la versión constructor de cadena? Es posible que su conexión a la base de datos está siendo cerrada. Si usted está haciendo una gran cantidad de concatenación, me gustaría ir w / StringBuilder, ya que es un poco más eficiente.

Una de las causas puede ser que las cadenas son inmutables en .Net lo que cuando se hace una operación en uno como concatenación que está creando en realidad una nueva cadena.

Otra posible causa es que la longitud de cadena es un int por lo que la longitud máxima posible es Int32.MaxValue o 2147483647.

En cualquier caso un StringBuilder es mejor que "cadena1 + cadena2" para este tipo de operación. A pesar de que, utilizando las capacidades XML integradas sería aún mejor.

string.Concat(string[]) es, con mucho, la forma más rápida para concatenar cadenas. Se litterly mata StringBuilder en el rendimiento cuando se utiliza en bucles, especialmente si crea la StringBuilder en cada iteración. Hay un montón de referencias si se busca en Google "c # formato de cadena vs StringBuilder" o algo por el estilo. http://www.codeproject.com/KB/cs/StringBuilder_vs_String.aspx le da una iDeer acerca de los tiempos. Aquí string.join gana la prueba de concatenación pero yo belive esto es debido a que el string.Concat(string, string) se utiliza en lugar de la versión sobrecargada que toma una matriz. Si se echa un vistazo en el código MSIL que se genera por los diferentes métodos que usted verá lo que pasa debajo del capó.

Aquí está mi tiro en la oscuridad ...

Las cadenas en .NET (no stringbuilders) entran en la cadena Intern piscina. Esto es básicamente un área gestionada por la CLR para compartir cuerdas para mejorar el rendimiento. Tiene que haber algún límite aquí, aunque no tengo ni idea de lo que es ese límite. Me imagino que toda la concatenación que está haciendo es golpear el techo del grupo de cadena pasante. Por lo que SQL dice que sí tengo un valor para ti, pero no se puede poner en cualquier lugar que pueda obtener una excepción.

Una prueba rápida y fácil sería nGen su montaje y ver si usted todavía consigue el error. Después nGen'ing, que la aplicación dejará de usar la piscina.

Si eso no funciona, me contacto con Microsoft para tratar de obtener algunos datos duros. Creo que mi idea suena plausible, pero no tengo idea de por qué funciona en modo de depuración. Tal vez en el modo de depuración cadenas no están internados. También soy ningún experto.

Cuando composición cadenas juntas siempre uso StringBuilder. Está diseñado para ello y es más eficiente que el simple uso de "cadena1 + cadena2".

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top