Pergunta

A minha pergunta é esta: É concatenação em C # segura? Se a string concatenação leva a erros inesperados, e substituir esse concatenação usando StringBuilder faz com que esses erros a desaparecer, o que poderia indicar?

Fundo: Estou desenvolvendo uma linha de comando pequena aplicação C #. Leva argumentos de linha de comando, executa uma consulta SQL um pouco complicado, e saídas cerca de 1300 linhas de dados em um arquivo XML formatado.

O meu programa inicial seria sempre correr bem no modo de depuração. No entanto, no modo de versão chegaria a sobre o resultado SQL 750, e depois morrer com um erro. O erro foi que uma determinada coluna de dados não pôde ser lido, mesmo através do método Read () do objeto SqlDataReader tinha acabado de voltar verdade.

Este problema foi corrigido usando StringBuilder para todas as operações no código, onde anteriormente não havia sido "string1 + string2". Eu não estou falando de concatenação dentro do loop de consulta SQL, onde StringBuilder já estava em uso. Eu estou falando sobre concatenations simples entre duas ou três variáveis ??seqüência curta anteriores no código.

Eu tive a impressão de que C # foi inteligente o suficiente para lidar com o gerenciamento de memória para adicionar algumas cordas juntos. Estou errado? Ou será que isso indica algum outro tipo de problema de código?

Foi útil?

Solução

Além de que você está fazendo é, provavelmente, o melhor feito com APIs XML em vez de cordas ou StringBuilder I dúvida de que o erro que você vê é devido a concatenação. Talvez a mudança para StringBuilder apenas mascarou o erro ou passaram-lo graciosamente, mas duvido usando cordas realmente foi a causa.

Outras dicas

Para responder à sua pergunta: contatenation string em C # (e .NET em geral) é "seguro", mas fazê-lo em um loop apertado como você descreve é ??susceptível de causar pressão de memória grave e tensão colocada sobre o coletor de lixo.

Eu arriscaria um palpite de que os erros que você fala foram relacionados à exaustão de recursos de algum tipo, mas seria útil se você pudesse fornecer mais detalhes - por exemplo, se você receber uma exceção? Será que o aplicativo terminar de forma anormal?

Fundo: cordas .NET são imutáveis, então quando você faz uma concatenação assim:

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

Este é mais ou menos equivalente ao seguinte:

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;

A finalidade deste exemplo é enfatizar que cada vez os resultados de loop na alocação de uma nova cadeia temporário.

Uma vez que as strings são imutáveis, o tempo de execução não tem opções alternativas, mas para alocar uma nova seqüência cada vez que você adicionar outra seqüência ao final do seu resultado.

Embora a corda result é constantemente atualizado para apontar para o resultado intermediário mais recente e maior, você está produzindo um lote destes corda temporário chamado-un que se tornar elegível para coleta de lixo quase imediatamente.

No final desta concatenação você terá as seguintes cadeias armazenadas na memória (supondo, para simplificar, que o coletor de lixo ainda não foi executado).

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";
// ...

Apesar de todas estas variáveis ??temporárias implícitas são elegíveis para coleta de lixo quase imediatamente, eles ainda têm que ser alocados. Ao realizar concatenação em um loop apertado isso vai colocar um monte de tensão sobre o coletor de lixo e, se nada mais, vai fazer o seu código executar muito lentamente. Tenho visto o impacto desta primeira mão performance, e torna-se verdadeiramente dramática como a sua cadeia concatenada torna-se maior.

A abordagem recomendada é usar sempre um StringBuilder se você está fazendo mais do que alguns concatenações de cadeia. StringBuilder usa um buffer mutável para reduzir o número de alocações que são necessárias na construção de sua corda.

concatenação de String é seguro embora mais memória do que usar um StringBuilder se contatenating grande número de cordas em um loop. E em casos extremos você pode estar ficando sem memória.

É quase certamente um bug em seu código.

Talvez você esteja contatenating um número muito grande de cordas. Ou talvez seja outra coisa completamente diferente.

Eu voltaria para depuração, sem quaisquer preconceitos da causa raiz -. Se você ainda está tendo problemas para tentar reduzi-lo ao mínimo necessário para repro o problema e código postal

Quanto tempo levaria a versão concatenação vs a versão seqüência de construtor? É possível que a conexão com o DB está sendo fechado. Se você está fazendo um monte de concatenação, eu iria w / StringBuilder, pois é um pouco mais eficiente.

Uma das causas pode ser que strings são imutáveis ??em .Net por isso, quando você faz uma operação em um como concatenação na verdade você está criando uma nova string.

Outra causa possível é que comprimento da corda é um int de modo que o comprimento máximo possível é Int32.MaxValue ou 2,147,483,647.

Em qualquer caso, um StringBuilder é melhor do que "string1 + string2" para este tipo de operação. Embora, usando o built-in capacidades XML seria ainda melhor.

string.Concat(string[]) é de longe a maneira mais rápida de cordas concatenar. Ele litterly mata StringBuilder no desempenho quando usado em loops, especialmente se você criar o StringBuilder em cada iteração. Há um monte de referências, se você Google "format c # corda vs stringbuilder" ou algo parecido. http://www.codeproject.com/KB/cs/StringBuilder_vs_String.aspx lhe dá uma iDeer sobre os tempos. Aqui String.Join vence o teste concatenação mas eu acredito isso é porque o string.Concat(string, string) é usada em vez da versão sobrecarregado que recebe um array. Se você der uma olhada no código MSIL que é gerado pelos diferentes métodos você verá o que acontecendo sob o capô.

Aqui está o meu tiro no escuro ...

Cordas em .NET (não StringBuilders) ir para o Intern Piscina cadeia. Esta é basicamente uma área gerida pela CLR para compartilhar cordas para melhorar o desempenho. Tem que haver algum limite aqui, embora eu não tenho nenhuma idéia do que esse limite é. I imaginar toda a concatenação que você está fazendo está atingindo o teto da piscina corda estagiário. Então SQL diz que sim eu tenho um valor para você, mas não pode colocá-lo em qualquer lugar para que você obtenha uma exceção.

Um teste rápido e fácil seria Ngen sua montagem e veja se você ainda obter o erro. Depois nGen'ing, sua aplicação não vai mais usar a piscina.

Se isso falhar, eu contato com a Microsoft para tentar obter alguns detalhes difíceis. Eu acho que minha idéia parece plausível, mas não tenho idéia por que ela funciona no modo de depuração. Talvez em cordas modo de depuração não estão internados. Eu também não sou especialista.

Quando compondo cordas juntos, eu sempre usar StringBuilder. Ele foi projetado para isso e é mais eficiente do que simplesmente usando "string1 + string2".

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top