Pergunta

Digamos que você queira gerar ou concatenar strings.Qual dos seguintes estilos você prefere?

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

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

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

Você prefere usar formato ou simplesmente concatenar strings?Qual é o seu favorito?Um desses está machucando seus olhos?

Você tem algum argumento racional para usar um e não o outro?

Eu iria para o segundo.

Foi útil?

Solução

Experimente este código.

É uma versão ligeiramente modificada do seu código.
1.Removi Console.WriteLine porque provavelmente é algumas ordens de magnitude mais lenta do que estou tentando medir.
2.Estou iniciando o Cronômetro antes do loop e parando logo depois, dessa forma não vou perder precisão se a função demorar por exemplo 26,4 ticks para ser executada.
3.A maneira como você dividiu o resultado por algumas iterações estava errada.Veja o que acontece se você tiver 1.000 milissegundos e 100 milissegundos.Em ambas as situações, você obterá 0 ms após dividir por 1.000.000.

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);

Esses são meus resultados:

1000000 x resultado = string.Format("{0} {1}", p.Nome, p.Sobrenome);pegou:618ms - 2213706 tiques
1000000 x resultado = (p.Nome + " " + p.Sobrenome);pegou:166ms - 595610 tiques

Outras dicas

Estou surpreso que tantas pessoas queiram encontrar imediatamente o código que executa mais rápido. Se UM MILHÃO de iterações AINDA levar menos de um segundo para ser processado, isso será de ALGUMA MANEIRA perceptível para o usuário final?Não muito provável.

Otimização prematura = FALHA.

eu iria com o String.Format opção, apenas porque faz mais sentido do ponto de vista arquitetônico.Não me importo com o desempenho até que se torne um problema (e se isso acontecesse, eu me perguntaria:Preciso concatenar um milhão de nomes de uma vez?Certamente nem todos caberão na tela...)

Considere se o seu cliente deseja alterá-lo posteriormente para que possa configurar se deseja exibir "Firstname Lastname" ou "Lastname, Firstname." Com a opção Formatar, isso é fácil – basta trocar a string de formato.Com o concat, você precisará de código extra.Claro que isso não parece grande coisa neste exemplo específico, mas extrapole.

Nossa - depois de ler uma das outras respostas tentei inverter a ordem das operações - realizando primeiro a concatenação, depois o String.Format ...

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

Então a ordem das operações faz uma enorme diferença, ou melhor, a primeira operação é SEMPRE muito mais lenta.

Aqui estão os resultados de uma execução em que as operações são concluídas mais de uma vez.Tentei alterar os pedidos, mas geralmente as coisas seguem as mesmas regras, uma vez que o primeiro resultado é 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 você pode ver, as execuções subsequentes do mesmo método (refatorei o código em três métodos) são cada vez mais rápidas.O mais rápido parece ser o método Console.WriteLine(String.Concat(...)) , seguido pela concatenação normal e depois pelas operações formatadas.

O atraso inicial na inicialização é provavelmente a inicialização do Console Stream, pois colocar um Console.Writeline("Start!") antes da primeira operação traz todos os tempos de volta à linha.

Strings são imutáveis, isso significa que o mesmo pequeno pedaço de memória é usado repetidamente em seu código.Adicionar as mesmas duas strings e criar a mesma string repetidamente não afeta a memória..Net é inteligente o suficiente para usar a mesma referência de memória.Portanto, seu código não testa verdadeiramente a diferença entre os dois métodos concat.

Experimente isto para ver o tamanho:

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();

Saída de amostra:

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

Tenha pena dos pobres tradutores

Se você saber seu aplicativo permanecerá em inglês, então tudo bem, salve os tiques do relógio.No entanto, muitas culturas normalmente veriam Sobrenome Nome, por exemplo, em endereços.

Então use string.Format(), especialmente se você quiser que seu aplicativo chegue a algum lugar onde o inglês não seja o primeiro idioma.

Aqui estão meus resultados em mais de 100.000 iterações:

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

E aqui está o código do 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");

Então, não sei de quem é a resposta marcar como resposta :)

Concatenar strings é bom em um cenário simples como esse - é mais complicado com qualquer coisa mais complicada do que isso, até mesmo Sobrenome, Nome.Com o formato você consegue ver, de relance, qual será a estrutura final da string ao ler o código, com a concatenação fica quase impossível discernir imediatamente o resultado final (exceto com um exemplo bem simples como este).

O que isso significa, no longo prazo, é que quando você voltar para fazer uma alteração no formato da string, você poderá entrar e fazer alguns ajustes na string de formato ou franzir a testa e começar a se mover por tudo. tipos de acessadores de propriedade misturados com texto, o que tem maior probabilidade de apresentar problemas.

Se estiver usando o .NET 3.5, você pode usar um método de extensão como este e obtenha uma sintaxe fácil e espontânea como esta:

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

Finalmente, à medida que seu aplicativo cresce em complexidade, você pode decidir que, para manter as strings em seu aplicativo de maneira sã, você deseja movê-las para um arquivo de recursos para localização ou simplesmente para um auxiliar estático.Isso será MUITO mais fácil de conseguir se você tiver usado formatos consistentemente e seu código puder ser simplesmente refatorado para usar algo como

string name = String.Format(ApplicationStrings.General.InformalUserNameFormat,this.FirstName,this.LastName);

Para uma manipulação muito simples, eu usaria a concatenação, mas quando você ultrapassa 2 ou 3 elementos, o formato se torna mais apropriado, IMO.

Outro motivo para preferir String.Format é que as strings .NET são imutáveis ​​e fazer isso dessa forma cria menos cópias temporárias/intermediárias.

Embora eu entenda totalmente a preferência de estilo e tenha escolhido a concatenação para minha primeira resposta, em parte com base em minha própria preferência, parte da minha decisão foi baseada no pensamento de que a concatenação seria mais rápida.Então, por curiosidade, testei e os resultados foram surpreendentes, principalmente para uma corda tão pequena.

Usando o seguinte 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");

Obtive os seguintes 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

Usar o método de formatação é 100 vezes mais lento!!A concatenação nem foi registrada como 1ms, e é por isso que também produzo os tiques do cronômetro.

Para concatenação básica de strings, geralmente uso o segundo estilo - mais fácil de ler e mais simples.No entanto, se estou fazendo uma combinação de strings mais complicada, geralmente opto por String.Format.

String.Format economiza muitas citações e vantagens ...

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

Apenas alguns caracteres foram salvos, mas acho que, neste exemplo, o formato o torna muito mais limpo.

Um teste melhor seria observar sua memória usando Perfmon e os contadores de memória CLR.Meu entendimento é que o motivo pelo qual você deseja usar String.Format em vez de apenas concatenar strings é que, como as strings são imutáveis, você está sobrecarregando desnecessariamente o coletor de lixo com strings temporárias que precisam ser recuperadas na próxima passagem.

StringBuilder e String.Format, embora potencialmente mais lentos, são mais eficientes em termos de memória.

O que há de tão ruim na concatenação de strings?

Geralmente prefiro o primeiro, pois especialmente quando as cordas ficam longas pode ser muito mais fácil de ler.

O outro benefício, acredito, é o desempenho, já que o último executa 2 instruções de criação de string antes de passar a string final para o método Console.Write.String.Format usa um StringBuilder nos bastidores, acredito, portanto, várias concatenações são evitadas.

Deve-se observar, entretanto, que se os parâmetros que você está passando para String.Format (e outros métodos como Console.Write) forem tipos de valor, eles serão incluídos na caixa antes de serem transmitidos, o que pode fornecer seus próprios resultados de desempenho. Postagem sobre isso aqui.

Daqui a uma semana, 19 de agosto de 2015, esta questão terá exatamente sete (7) anos.Agora existe uma maneira melhor de fazer isso. Melhorar em termos de manutenção, já que não fiz nenhum teste de desempenho em comparação com apenas a concatenação de strings (mas isso importa hoje em dia?alguns milissegundos de diferença?).A nova maneira de fazer isso com C#6.0:

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

Este novo recurso é melhorar, OMI e na verdade melhor no nosso caso pois temos códigos onde construímos querystrings cujos valores dependem de alguns fatores.Imagine uma string de consulta onde temos 6 argumentos.Então, em vez de fazer, por exemplo:

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

in pode ser escrito assim e é mais fácil de ler:

var qs=$"q1={someVar}&q2={anotherVarWithLongName}&q3={var3}&q4={var4}&q5={var5}&q6={var6}";

A partir do C# 6.0 strings interpoladas pode ser usado para fazer isso, o que simplifica ainda mais o formato.

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

Uma expressão de string interpolada se parece com uma string de modelo que contém expressões.Uma expressão de string interpolada cria uma string substituindo as expressões contidas pelas representações ToString dos resultados das expressões.

Strings interpoladas têm desempenho semelhante a String.Format, mas melhor legibilidade e sintaxe mais curta, devido ao fato de que valores e expressões são inseridos em linha.

Consulte também este artigo dotnetperls na interpolação de strings.

Se você está procurando uma maneira padrão de formatar suas strings, isso faz sentido em termos de legibilidade e desempenho (exceto se microssegundos fizerem diferença em seu caso de uso específico).

  1. A formatação é a maneira “.NET” de fazer isso.Certas ferramentas de refatoração (Refactor!por exemplo) irá até propor refatorar o código do estilo concat para usar o estilo de formatação.
  2. A formatação é mais fácil de otimizar para o compilador (embora a segunda provavelmente seja refatorada para usar o método 'Concat', que é rápido).
  3. A formatação geralmente é mais clara de ler (especialmente com formatação “sofisticada”).
  4. Formatação significa chamadas implícitas para '.ToString' em todas as variáveis, o que é bom para facilitar a leitura.
  5. De acordo com o “C# Efetivo”, as implementações 'WriteLine' e 'Format' do .NET estão confusas, elas colocam automaticamente todos os tipos de valor (o que é ruim).“C # eficaz” aconselha executar chamadas '.ToString' explicitamente, o que IMHO é falso (consulte Postagem de Jeff)
  6. No momento, as dicas de tipo de formatação não são verificadas pelo compilador, resultando em erros de tempo de execução.No entanto, isso poderá ser alterado em versões futuras.

Eu usaria String.Format, mas também teria a string de formato nos arquivos de recursos para que pudesse ser localizada para outros idiomas.Usar uma string concat simples não permite que você faça isso.Obviamente, se você nunca precisar localizar essa string, isso não é motivo para pensar nisso.Realmente depende da finalidade da string.

Se for mostrado ao usuário, eu usaria String.Format para poder localizar se precisar - e FxCop vou verificar a ortografia para mim, só para garantir :)

Se contiver números ou qualquer outra coisa que não seja string (por exemplodatas), eu usaria String.Format porque me dá mais controle sobre a formatação.

Se for para construir uma consulta como SQL, eu usaria Linq.

Se fosse para concatenar strings dentro de um loop, eu usaria StringBuilder para evitar problemas de desempenho.

Se for para alguma saída que o usuário não verá e não afetará o desempenho, eu usaria String.Format porque tenho o hábito de usá-lo de qualquer maneira e estou acostumado :)

Se você estiver lidando com algo que precisa ser fácil de ler (e isso é a maior parte do código), eu ficaria com a versão de sobrecarga do operador, A MENOS:

  • O código precisa ser executado milhões de vezes
  • Você está fazendo toneladas de concats (mais de 4 é uma tonelada)
  • O código é direcionado para a Estrutura Compacta

Em pelo menos duas dessas circunstâncias, eu usaria o StringBuilder.

Eu escolho com base na legibilidade.Prefiro a opção de formato quando há algum texto em torno das variáveis.Neste exemplo:

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

você entende o significado mesmo sem nomes de variáveis, enquanto o concat está cheio de aspas e sinais + e confunde meus olhos:

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

(Peguei emprestado o exemplo de Mike porque gosto)

Se a string de formato não significa muito sem nomes de variáveis, tenho que usar concat:

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

A opção de formato me faz ler os nomes das variáveis ​​e mapeá-las para os números correspondentes.A opção concat não exige isso.Ainda estou confuso com as aspas e os sinais +, mas a alternativa é pior.Rubi?

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

Em termos de desempenho, espero que a opção de formato seja mais lenta que o concat, já que o formato exige que a string seja analisado.Não me lembro de ter que otimizar esse tipo de instrução, mas se o fizesse, daria uma olhada string métodos como Concat() e Join().

A outra vantagem do formato é que a string de formato pode ser colocada em um arquivo de configuração.Muito útil com mensagens de erro e texto da interface do usuário.

Se você pretende localizar o resultado, String.Format é essencial porque diferentes linguagens naturais podem nem ter os dados na mesma ordem.

Acho que isso depende muito de quão complexa é a saída.Costumo escolher o cenário que funciona melhor no momento.

Escolha a ferramenta certa com base no trabalho :D A que parecer mais limpa!

Prefiro também a segunda, mas não tenho neste momento argumentos racionais para apoiar essa posição.

Agradável!

Acabei de adicionar

        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();

E é ainda mais rápido (acho que string.Concat é chamado em ambos os exemplos, mas o primeiro requer algum tipo de tradução).

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

Como não acho que as respostas aqui cubram tudo, gostaria de fazer um pequeno acréscimo aqui.

Console.WriteLine(string format, params object[] pars) chamadas string.Format.O '+' implica concatenação de strings.Não creio que isso tenha sempre a ver com estilo;Costumo misturar os dois estilos dependendo do contexto em que estou.

Resposta curta

A decisão que você está enfrentando tem a ver com a alocação de strings.Vou tentar simplificar.

Diga que você tem

string s = a + "foo" + b;

Se você executar isso, será avaliado da seguinte forma:

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

tmp aqui não é realmente uma variável local, mas é temporária para o JIT (é colocada na pilha IL).Se você colocar uma string na pilha (como ldstr em IL para literais), você coloca uma referência a um ponteiro de string na pilha.

No momento em que você liga concat esta referência se torna um problema, porque não há nenhuma referência de string disponível que contenha ambas as strings.Isso significa que o .NET precisa alocar um novo bloco de memória e, em seguida, preenchê-lo com as duas strings.A razão pela qual isto é um problema é porque a alocação é relativamente cara.

O que muda a pergunta para:Como você pode reduzir o número de concat operações?

Então, a resposta aproximada é: string.Format para> 1 concat, '+' funcionará perfeitamente para 1 concat.E se você não se importa em fazer otimizações de microdesempenho, string.Format funcionará muito bem no caso geral.

Uma nota sobre Cultura

E depois há algo chamado cultura...

string.Format permite que você use CultureInfo na sua formatação.Um operador simples '+' usa a cultura atual.

Esta é uma observação especialmente importante se você estiver escrevendo formatos de arquivo e f.ex. double valores que você 'adiciona' a uma string.Em máquinas diferentes, você pode acabar com strings diferentes se não usar string.Format com uma explícita CultureInfo.

F.ex.Considere o que acontece se você mudar um '.' para um '' 'enquanto escreva seu arquivo de valores de vírgula ...em holandês, o separador decimal é uma vírgula, então seu usuário pode ter uma surpresa 'engraçada'.

Resposta mais detalhada

Se você não sabe o tamanho exato da string de antemão, é melhor usar uma política como esta para superalocar os buffers que você usa.O espaço livre é preenchido primeiro, após o qual os dados são copiados.

Crescer significa alocar um novo bloco de memória e copiar os dados antigos para o novo buffer.O antigo bloco de memória pode então ser liberado.Você obtém o resultado final neste ponto:crescer é uma operação cara.

A maneira mais prática de fazer isso é usar uma política de superalocação.A política mais comum é superalocar buffers em potências de 2.Claro, você tem que fazer isso um pouco mais inteligente do que isso (já que não faz sentido crescer de 1,2,4,8 se você já sabe que precisa de 128 caracteres), mas você entendeu.A política garante que você não precise de muitas das operações caras que descrevi acima.

StringBuilder é uma classe que basicamente superaloca o buffer subjacente em potências de dois. string.Format usa StringBuilder sob o capô.

Isso torna sua decisão uma troca básica entre overlocate-and-append(-multiple) (w/w.o.cultura) ou apenas alocar e anexar.

Pessoalmente, o segundo, já que tudo o que você está usando está na ordem direta em que será produzido.Enquanto no primeiro você precisa combinar {0} e {1} com a var adequada, o que é fácil de bagunçar.

Pelo menos não é tão ruim quanto o sprintf do C++, onde se você errar o tipo de variável, a coisa toda explodirá.

Além disso, como o segundo está todo embutido e não é necessário fazer nenhuma pesquisa e substituição de todas as coisas {0}, o último deve ser mais rápido...embora eu não tenha certeza.

Na verdade, gosto do primeiro porque quando há muitas variáveis ​​misturadas ao texto, parece-me mais fácil de ler.Além disso, é mais fácil lidar com aspas ao usar o formato string.Format(), uh,.Aqui está análise decente de concatenação de strings.

Sempre segui o caminho string.Format().Ser capaz de armazenar formatos em variáveis ​​como o exemplo do Nathan é uma grande vantagem.Em alguns casos, posso acrescentar uma variável, mas quando mais de uma variável está sendo concatenada, refatoro para usar a formatação.

Ah, e apenas para completar, o seguinte é alguns ticks mais rápido que a concatenação normal:

Console.WriteLine(String.Concat(p.FirstName," ",p.LastName));

O primeiro (formato) me parece melhor.É mais legível e você não está criando objetos de string temporários extras.

Fiquei curioso para saber qual era a posição do StringBuilder com esses testes.Resultados abaixo...

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

De acordo com o material de preparação do MCSD, a Microsoft sugere usar o operador + ao lidar com um número muito pequeno de concatenações (provavelmente 2 a 4).Ainda não sei por que, mas é algo a considerar.

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