Back-End

10 ago, 2018

C# – Os erros mais comuns cometidos pelos iniciantes – Parte 01

Publicidade

Hoje veremos alguns dos erros mais comuns cometidos por 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 atribuídos 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:

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

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 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 possuem 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:

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ções 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.

Dessa forma, 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.