C# -  Os erros mais comuns cometidos pelos iniciantes - I


Hoje veremos alguns dos erros mais comuns cometidos pelos iniciantes e não iniciantes na linguagem C#.

Todos nós cometemos erros, não importa o nível de conhecimento que temos sobre um assunto. Com os desenvolvedores ocorre o mesmo problema, afinal somos apenas humanos.

Fiz uma compilação dos erros mais comuns cometidos pelos iniciantes, e, também pelos não iniciantes, ao usar a linguagem C#. O importante é reconhecer que erramos e tratar de não repetir o erro.

Os exemplos usados foram simplificados e ajustados para focar na descrição, reconhecimento e solução do erro.

Nas referências estão as fontes de onde os exemplos foram obtidos, adaptados e ajustados.

Recursos usados:

1 - Usando um tipo de referência como valor e vice-versa

Na linguagem C# não é quem instância o objeto e atribui um valor a uma variável quem decide se os valores atribuidos são valores por tipo ou por referência.  A decisão foi tomada pelo programador que definiu o objeto.

Assim você precisa conhecer se o objeto que você esta usando é um tipo por valor ou por referência para evitar surpresas desagradáveis.

Como esse aqui... 

Point ponto1 = new Point(200, 300);
Point ponto2 = ponto1;
ponto2.X = 500;
MessageBox.Show("ponto1.X = " + ponto1.X.ToString());       // valor 200 
MessageBox.Show("ponto2.X = " + ponto2.X.ToString());       // valor 500
O valor de ponto1 permanece inalterado quando um novo valor de coordenada X é atribuído a ponto2.

Point é uma struct :  public struct Point {...}  e define um tipo por valor;

ponto1 e ponto2 contém cada um sua própria cópia de um objeto Point.

 

Os objetos Point e Pen são criados da mesma maneira mas o comportamento é diferente:

Pen caneta1 = new Pen(Color.Orange);
Pen caneta2 = caneta1;
caneta2.Color = Color.Yellow;
MessageBox.Show("caneta1.Color = " + caneta1.Color.ToString());   // valor Yellow
MessageBox.Show("caneta2.Color = " + caneta2.Color.ToString());
O valor de caneta1 será modificado quando uma nova cor for atribuída a caneta2.

Pen é uma classe :  public class Pen {...}  e define um tipo por referência;

caneta1 e caneta2 contém referências ao mesmo objeto Pen

 

Dessa forma se você depender de algum comportamento que é diferente entre os tipos de valor e referência - como a  capacidade de passar um objeto como um parâmetro de método e fazer com que esse método mude o estado do objeto - certifique-se de estar lidando com o tipo correto de objeto para evitar problemas.

2 - Não compreender os valores padrão para variáveis não inicializadas

No C# 2.0 foram introduzidos os nullable types ou tipos anuláveis que permitem atribuir um valor null a uma variável de tipo por valor. A sintaxe abreviada para definir um tipo anulável é usar o símbolo ? ao lado da definição do tipo. Ex: int? , long? .

Por padrão, os tipos tipos de valor não podem ser nulos e por definição, eles têm um valor inicial e mesmo variáveis ​​não inicializadas de tipos de valor devem ter um valor. Isso é chamado de valor padrão para esse tipo. Isso leva ao seguinte resultado geralmente inesperado ao verificar se uma variável não é inicializada:

No código acima o VS 2017 vai alertar que a expressão valor == null sempre vai ser 'false' mas o programa vai compilar.

Como valor é uma variável do tipo por valor (é um int), o seu valor padrão é 0, logo é not null.

A variável data é do tipo DateTime que é uma struct, e, possui o valor padrão igual a 01/01/0001 00:00:00 quando não inicializada.

Muitos tipor por valor possuem a propriedade IsEmpty que você pode usar para verificar se o seu valor é igual ao valor padrão.

Assim ao verificar se uma variável foi inicializada ou não, leve em conta seu tipo e o valor da variável não inicializada para aquele tipo pois nem todas as variáveis não inicializadas possue valor null.

3 - Comparar strings de forma incorreta

Primeiro, string é um tipo por referência, segundo, strings são imutáveis e terceiro, existem muitas maneiras de compararmos strings na linguagem C#.

Talvez a maneira mais usada para comparar strings é utilizar o operador ==,  Ex:   string1 == string2

Uma outra forma é usar o método Equals. Mas observe que eles atuam de forma um pouco diferente:

Enquanto o operador == compara retornos de referência true quando ambas as referências apontam para o mesmo objeto, Equals() compara o objeto por valor e retornará true se as referências apontarem para objetos que são equivalentes.

Então qual é melhor ?

Usar o operador == não é a maneira mais eficiente de comparar strings pois ele não especifica explicitamente no código qual o tipo de comparação é aplicado.

A maneira mais eficiente de comparar se duas strings são iguais é usar o método Equals e temos duas sobrecargas que podem ser usadas:

public bool Equals(string value);
public bool Equals(string value, StringComparison comparisonType);

O primeiro método (sem o parâmetro comparisonType), se comporta da mesma forma que o operador ==, mas tem o benefício de ser explicitamente aplicada a cadeias de caracteres. Ele realiza uma comparação ordinal das cadeias de caracteres, que é basicamente uma comparação byte a byte.  Em muitos casos, esse é exatamente o tipo de comparação que você deseja, especialmente ao comparar cadeias cujos valores são definidos via código, como nomes de arquivos, variáveis ​​de ambiente, atributos etc.

Nesses casos, desde que uma comparação ordinal seja de fato o tipo correto de comparação para essa situação, a única desvantagem de usar o método Equals sem um comparisonType é que alguém que lê o código pode não saber que tipo de comparação você está fazendo.

Na segunda a assinatura do método Equals, que inclui um comparisonType toda vez que você comparar strings, não apenas tornará seu código mais claro, mas também fará com que você pense explicitamente sobre o tipo de comparação que você precisa fazer.

As opções disponíveis para comparisonType são:

Nome do membro

Descrição

CurrentCulture
Compara cadeias de caracteres usando regras de classificação sensíveis à cultura e a cultura atual.
CurrentCultureIgnoreCase
Compara cadeias de caracteres usando regras de classificação sensíveis à cultura, a cultura atual e ignorando o padrão de maiúsculas e minúsculas das cadeias de caracteres que estão sendo comparadas.
InvariantCulture
Compara cadeias de caracteres usando regras de classificação sensíveis à cultura e a cultura invariável.
InvariantCultureIgnoreCase
Compara cadeias de caracteres usando regras de classificação sensíveis à cultura, a cultura invariável e ignorando o padrão de maiúsculas e minúsculas das cadeias de caracteres que estão sendo comparadas.
Ordinal
Compara cadeias de caracteres usando regras de classificação ordinal (binária).
OrdinalIgnoreCase
Compara cadeias de caracteres usando regras de classificação ordinal (binária) e ignorando o padrão de maiúsculas e minúsculas das cadeias de caracteres que estão sendo comparadas.

Para comparar strings que foram inseridas pelo usuário ou que devem ser exibidas ao usuário, use uma comparação sensível à cultura (CurrentCulture ou CurrentCultureIgnoreCase).

Para comparar strings definidas via código, use a comparação ordinal (Ordinal ou OrdinalIgnoreCase).

As enumeração InvariantCulture e InvariantCultureIgnoreCase não devem ser usadas, exceto em circunstâncias muito limitadas, porque as comparações ordinais são mais eficientes. Se uma comparação de cultura for necessária, ela geralmente deve ser executada contra a cultura atual ou outra cultura específica.

Faltou falar do método Compare que fornece informação sobre a ordem relativa das strings e não verifica a igualdade.

Assim a sobrecarga Compare(string1, string2) vai comparar os dois objetos strings e vai retornar um inteiro (menor, igual ou maior que zero) que indica a sua posição relativa na ordem de classificação.

Assim ele não é usado para verificar se duas strings são iguais.

Na segunda parte do artigo vou continuar a falar sobre os erros mais comuns.

Aguarde...

"E os que são de Cristo crucificaram a carne com as suas paixões e concupiscências.
Se vivemos em Espírito, andemos também em Espírito.
Não sejamos cobiçosos de vanglórias, irritando-nos uns aos outros, invejando-nos uns aos outros."
Gálatas 5:24-26

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti