Desenvolvimento - C#Feed de artigos deste autor

Strings em C# - Coisas que nem todos sabem
por Marcio Paulo Mello Martins



Descrição

Este artigo ilustra os erros comuns na utilização de Strings, além de dicas sobre como melhorar a performance de aplicações que manipulam dados em forma de texto.

Introdução

Todo mundo conhece strings (para ser mais exato, uma instância da classe System.String), certo? Sim ... sequências de caracteres são comuns quando se manipula texto. Aliás, todo texto é uma string. Então, todo mundo está careca de saber como se trabalha com strings, certo?

ERRADO!

Já vi muita gente usando strings de forma errada, e isso é muito mais comum do que se pensa.

Vamos enumerar aqui alguns casos e dicas que merecem ser vistos pela maioria dos desenvolvedores.

1  - Obter a referencia uma String através de um Object

Um dos erros mais gritantes que se pode cometer utilizando strings é quando se obtém a referência de uma string cuja instância é um Object. Por exemplo, imagine que você tem um DataTable contendo uma DataColumn cujo tipo é String; aí você quer pegar o valor de um elemento que está em uma DataRow, e faz o seguinte:

Caixa de texto: string str = dataTable.Rows[0][1].ToString();

O objeto retornado pela chamada de dataTable.Rows[0][1] é do tipo Object  mas, no nosso caso, já contém um valor do tipo String,  o que desobriga o desenvolvedor a chamar o método ToString() para esta instância. Toda vez que chamamos o método ToString(), ele cria uma nova string que conterá o valor a ser retornado. Ou seja, teremos duas instâncias de String contendo exatamente o mesmo conteúdo na memória, o que é redundante e causa menor performance. O correto é fazer um cast direto, desta forma:

Caixa de texto: string str = (string)dataTable.Rows[0][1];

Desta forma, o compilador entende que o valor passado já é do tipo String, e passa a referência da memória diretamente para o objeto, sem necessidade de processamento ou criação de novos objetos internamente.

Agora, se seu dado pode ser nulo, a coisa muda de figura.

Caso o dado que você está passando para uma string possa ser um DbNull (nulo no banco de dados), aí sim eu RECOMENDO e ENFATIZO o uso do método ToString() como demonstrado no primeiro exemplo, pois este método converte um dado nulo para uma string vazia, evitando problemas de conversão do tipo DbNull.Value para String.

Portanto, CUIDADO !!

2 - Concatenação de String

Isso é uma novela mexicana ... todo mundo fala, todo mundo recomenda, mas poucos fazem da forma correta.

Quando se modifica o conteúdo de uma String, não se modifica o conteúdo de uma String!  Uma nova String é criada na memória contendo a concatenação das duas Strings, e a nova referência é passada para a variável. Portanto, ao concatenarmos strings, criamos instâncias órfãs na memória.

Aí você me diz: "Ah, Marcio ... você é um Mané! O Garbage Collector recolhe esse lixo da memória!" Sim, claro que recolhe. Então, isso não causa impacto se seu escopo for aplicações Desktop. Mas se estivermos falando de aplicações Web, Windows Services ou de WCF Services, com milhares de solicitações por segundo? Isso poderia gerar quantidades absurdas de strings perdidas na memória!

Então, ao invés de fazer isto:

          Caixa de texto: string str = "Marcio ";
str += "Paulo";

Faça isto:

          Caixa de texto: StringBuilder sb = new StringBuilder();
sb.Append("Marcio ");
sb.Append("Paulo");
string str = sb.ToString();

Usando a classe StringBuilder você consegue efetuar milhares de concatenações por segundo, de forma rápida e otimizada, sem gerar resíduos na memória. Poderíamos até chamar de uma "Concatenação Ecológica"!

3  - Comparação de Strings

Quase todo mundo tem dúvidas nesta questão. Qual é a melhor forma para comparar se duas strings são iguais?  Alguns usam o comparador de igualdade (==), ou o método Equals, desta forma:

          Caixa de texto: bool resultado = a == b;

ou

Caixa de texto: bool resultado = a.Equals(b);

Claro ... dá certo. Mas e se um dos objetos for nulo? Aí lascou ...

Mas em verdade, em verdade vos digo: existe um meio mais eficiente de comparar strings, inclusive verificando se o objeto é nulo, levando-se em conta (ou não) o casing (maiúsculas e minúsculas)! Basta utilizar o método String.Compare(string a, string b, bool ignoreCase). Veja:

Caixa de texto: bool resultado = String.Compare(a, b, true) == 0;

Na verdade, este método retorna o seguinte:

· -1, se a maior que b;

· 0 , se a igual a b;

· 1, se menor que b;

Então já sabe: String.Compare ... Comparou, usou!

4 - Verificação de Strings vazias

Meu amigo... pelo amor de Deus! Não faça como o infeliz que escreveu a instrução abaixo:

Caixa de texto: if (str == "" || str == null)

Se você precisa testar se uma string é nula ou vazia, use o método String.IsNullOrEmpty(string a). Veja:

Caixa de texto: if (String.IsNullOrEmpty(str))

Este método é muito mais eficiente, já que é otimizado para verificar rapidamente se uma String é nula ou vazia.

5  - String.Empty versus "" ... ESQUEÇA !!

Há um debate em todas as galáxias do universo conhecido sobre este tema: qual é a melhor notação para descrever uma string vazia - String.Empty ou ""?

Na verdade, não existe uma diferença significante entre uma ou outra opção. Testes mostram que a diferença de performance entre uma e outra forma é desprezível, mesmo quando são criadas bilhões de strings vazias.

6 - Criação de strings com elementos repetidos

Já vi formas mirabolantes de preencher strings com caracteres repetidos, mas queria apenas mostrar a que considero mais simples:

Caixa de texto: string s = new string('*', 20);

Desta forma, estamos criando uma string contendo vinte caracteres '*' (asterisco). Simples, não?

7 - IndexOf com case insensitive

A  classe String possui várias implementações do método IndexOf, que localiza em uma string a posição de outra string dada. O problema é que todas as implementações são "case sensitive", ou seja, levam em consideração caracteres maiúsculos e minúsculos.

O  que pouca gente sabe é que, para resolver este problema, existe a classe CompareInfo dentro do namespace Globalization.  Esta classe possui um método IndexOf que não leva em conta maiúsculas e minúsculas (case insensitive). Veja:

Caixa de texto: using System.Globalization;

string s1 = "Trabalhar com C# é DEMAIS!"; string s2 = "demais";
CompareInfo Compare = CultureInfo.InvariantCulture.CompareInfo;
int i = Compare.IndexOf(s1, s2, CompareOptions.IgnoreCase);

Desta forma, teremos o índice do primeiro caractere da expressão “DEMAIS”, mas usando como padrão sua forma minúscula “demais”.

8 – Conversão de string para números

Este é um ponto que também é alvo de incompreensão e equívocos. Como converter uma string para um número? Muito simples.

Cada tipo numérico possui um método estático chamado TryParse. Para converter uma string num tipo numérico específico, basta criar uma variável do tipo desejado e passá-la como parâmetro de saída do método TryParse. Assim:

Caixa de texto: string s = "42";
int i;
if (int.TryParse(s, out i))
{
    //Conversão OK
}
else
{
    //Conversão Não OK
}

Conclusão

Existem zilhões de maneiras de se utilizar strings, mas nem todas são as mais indicadas para determinados casos.

O importante é que você analise seu caso e entenda as implicações da utilização de certos tratamentos para strings.

Usando as técnicas recomendadas acima, você estará de acordo com as melhores práticas utilizadas no mercado de desenvolvimento nos dias de hoje.

Até a próxima!

Marcio Paulo Mello Martins

Marcio Paulo Mello Martins - Bacharel em Ciência da Computação pela FASP; MCP, MCAD, MCSD, MCTS, MCPD e MCT. Atua há mais de 10 anos com desenvolvimento de software e treinamento em tecnologias Microsoft, trabalhando hoje como Analista Desenvolvedor na F|Camara (http://www.fcamara.com.br), além de ser proprietário da Logical Docs (http://www.logicaldocs.com.br), empresa do ramo de gerenciamento eletrônico de documentos. Quando sobra um tempinho, é pianista e toca em uma banda de Jazz.


Comentários

blog comments powered by Disqus