portaldacalheta.pt
  • Principal
  • Ágil
  • Américas
  • Processos Financeiros
  • Design Ux
Tecnologia

Código C # com erros: os 10 erros mais comuns na programação C #



Sobre C Sharp

C # é um dos vários idiomas que visam o Microsoft Common Language Runtime (CLR). As linguagens voltadas para o CLR se beneficiam de recursos como integração entre linguagens e tratamento de exceções, segurança aprimorada, um modelo simplificado para interação de componentes e serviços de depuração e criação de perfil. Das linguagens CLR de hoje, C # é a mais usada para aplicações profissionais complexas projetos de desenvolvimento que têm como alvo os ambientes de desktop, móvel ou servidor do Windows.

C # é uma linguagem orientada a objetos e fortemente tipada. A verificação estrita de tipo em C #, tanto em tempos de compilação quanto de execução, resulta na maioria dos erros de programação C # típicos sendo relatados o mais cedo possível, e suas localizações identificadas com bastante precisão. Isso pode economizar muito tempo em Programação C Sharp , em comparação com rastrear a causa de erros intrigantes que podem ocorrer muito depois que a operação ofensiva ocorre em linguagens que são mais liberais com sua aplicação de segurança de tipo. No entanto, muitos programadores C # involuntariamente (ou descuidadamente) jogam fora os benefícios dessa detecção, o que leva a alguns dos problemas discutidos neste tutorial C #.



Sobre este tutorial de programação C Sharp

Este tutorial descreve 10 dos erros de programação C # mais comuns cometidos, ou problemas a serem evitados, por programadores C # e fornece ajuda a eles.



Embora a maioria dos erros discutidos neste artigo sejam específicos do C #, alguns também são relevantes para outras linguagens que visam o CLR ou fazem uso do Framework Class Library (FCL).



Erro comum de programação em C # 1: usar uma referência como um valor ou vice-versa

Os programadores de C ++ e de muitas outras linguagens estão acostumados a controlar se os valores que atribuem às variáveis ​​são simplesmente valores ou referências a objetos existentes. Na programação C Sharp, entretanto, essa decisão é tomada pelo programador que escreveu o objeto, não pelo programador que instancia o objeto e o atribui a uma variável. Este é um problema comum para quem está tentando aprender programação C #.

Se você não sabe se o objeto que está usando é um tipo de valor ou de referência, pode ter algumas surpresas. Por exemplo:



Point point1 = new Point(20, 30); Point point2 = point1; point2.X = 50; Console.WriteLine(point1.X); // 20 (does this surprise you?) Console.WriteLine(point2.X); // 50 Pen pen1 = new Pen(Color.Black); Pen pen2 = pen1; pen2.Color = Color.Blue; Console.WriteLine(pen1.Color); // Blue (or does this surprise you?) Console.WriteLine(pen2.Color); // Blue

Como você pode ver, tanto o Point e Pen os objetos foram criados exatamente da mesma maneira, mas o valor de point1 permaneceu inalterado quando um novo X o valor da coordenada foi atribuído a point2, enquanto o valor de pen1 foi modificado quando uma nova cor foi atribuída a pen2. Podemos portanto deduzir que point1 e point2 cada um contém sua própria cópia de um Point objeto, enquanto pen1 e pen2 contêm referências ao mesmo Pen objeto. Mas como podemos saber disso sem fazer este experimento?

A resposta é olhar para as definições dos tipos de objeto (que você pode fazer facilmente no Visual Studio colocando o cursor sobre o nome do tipo de objeto e pressionando F12):



public struct Point { ... } // defines a “value” type public class Pen { ... } // defines a “reference” type

Conforme mostrado acima, na programação C #, o struct palavra-chave é usada para definir um tipo de valor, enquanto class palavra-chave é usada para definir um tipo de referência. Para aqueles com experiência em C ++, que foram enganados por uma falsa sensação de segurança pelas muitas semelhanças entre palavras-chave C ++ e C #, esse comportamento provavelmente é uma surpresa que pode fazer você pedir ajuda em um tutorial de C #.

Se você vai depender de algum comportamento que difere entre os tipos de valor e de 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 de programação C #.



Erro comum de programação C # 2: não entendendo os valores padrão para variáveis ​​não inicializadas

Em C #, os tipos de valor não podem ser nulos. Por definição, os tipos de valor têm um valor e mesmo as variáveis ​​não inicializadas dos 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 foi inicializada:

class Program { static Point point1; static Pen pen1; static void Main(string[] args) { Console.WriteLine(pen1 == null); // True Console.WriteLine(point1 == null); // False (huh?) } }

Por que não point1 nulo? A resposta é que Point é um tipo de valor e o valor padrão para um Point é (0,0), não nulo. Deixar de reconhecer isso é um erro muito fácil (e comum) de cometer em C #.



Muitos (mas não todos) tipos de valor têm um IsEmpty propriedade que você pode verificar para ver se é igual ao seu valor padrão:

Console.WriteLine(point1.IsEmpty); // True

Ao verificar se uma variável foi inicializada ou não, certifique-se de saber qual valor uma variável não inicializada desse tipo terá por padrão e não conte com o fato de ser nula.



Erro comum de programação em C # 3: uso de métodos de comparação de strings impróprios ou não especificados

Existem muitas maneiras diferentes de comparar strings em C #.

Embora muitos programadores usem o == operador para comparação de strings, é na verdade um dos menos métodos desejáveis ​​a serem empregados, principalmente porque não especifica explicitamente no código que tipo de comparação é desejado.

Em vez disso, a maneira preferida de testar a igualdade de strings na programação C # é com Equals método:

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

A primeira assinatura do método (ou seja, sem o parâmetro comparisonType), é realmente o mesmo que usar o == operador, mas tem a vantagem de ser explicitamente aplicado a strings. Ele executa uma comparação ordinal das strings, que é basicamente uma comparação byte a byte. Em muitos casos, este é exatamente o tipo de comparação que você deseja, especialmente ao comparar strings cujos valores são definidos programaticamente, como nomes de arquivo, variáveis ​​de ambiente, atributos, etc. Nesses casos, contanto que uma comparação ordinal seja realmente o tipo correto de comparação para essa situação, a única desvantagem de usar o Equals método sem um comparisonType é que alguém lendo o código pode não saber que tipo de comparação você está fazendo.

Usando o Equals assinatura de método que inclui um comparisonType cada vez que você compara strings, no entanto, não apenas deixará seu código mais claro, mas também fará com que você pense explicitamente sobre que tipo de comparação precisa fazer. Isso é algo que vale a pena fazer, porque mesmo que o inglês não forneça muitas diferenças entre as comparações ordinais e sensíveis à cultura, outros idiomas fornecem muitas, e ignorar a possibilidade de outros idiomas está se abrindo para um grande potencial para erros no caminho. Por exemplo:

string s = 'strasse'; // outputs False: Console.WriteLine(s == 'straße'); Console.WriteLine(s.Equals('straße')); Console.WriteLine(s.Equals('straße', StringComparison.Ordinal)); Console.WriteLine(s.Equals('Straße', StringComparison.CurrentCulture)); Console.WriteLine(s.Equals('straße', StringComparison.OrdinalIgnoreCase)); // outputs True: Console.WriteLine(s.Equals('straße', StringComparison.CurrentCulture)); Console.WriteLine(s.Equals('Straße', StringComparison.CurrentCultureIgnoreCase));

A prática mais segura é sempre fornecer um comparisonType parâmetro para o Equals método. Aqui estão algumas diretrizes básicas:

  • Ao comparar cadeias de caracteres que foram inseridas pelo usuário ou devem ser exibidas para o usuário, use uma comparação sensível à cultura (CurrentCulture ou CurrentCultureIgnoreCase).
  • Ao comparar strings programáticas, use comparação ordinal (Ordinal ou OrdinalIgnoreCase).
  • InvariantCulture e InvariantCultureIgnoreCase geralmente não devem ser usados, exceto em circunstâncias muito limitadas, porque as comparações ordinais são mais eficientes. Se uma comparação baseada na cultura for necessária, geralmente ela deve ser realizada em relação à cultura atual ou outra cultura específica.

Além de Equals método, as strings também fornecem o Compare método, que fornece informações sobre a ordem relativa das strings em vez de apenas um teste de igualdade. Este método é preferível a <, <=, > e >= operadores, pelas mesmas razões discutidas acima - para evitar problemas de C #.

Relacionado: 12 perguntas essenciais da entrevista sobre .NET

Erro comum de programação em C # 4: usando instruções iterativas (em vez de declarativas) para manipular coleções

Em C # 3.0, a adição de Consulta Integrada à Linguagem (LINQ) para a linguagem mudou para sempre a maneira como as coleções são consultadas e manipuladas. Desde então, se estiver usando instruções iterativas para manipular coleções, você não usou o LINQ quando provavelmente deveria.

aprenda rápido ou objetivo c

Alguns programadores C # nem sabem da existência do LINQ, mas felizmente esse número está se tornando cada vez mais pequeno. Muitos ainda pensam, porém, que, devido à semelhança entre as palavras-chave do LINQ e as instruções SQL, seu único uso é em código que consulta bancos de dados.

Embora a consulta de banco de dados seja um uso predominante de instruções LINQ, elas realmente funcionam em qualquer coleção enumerável (ou seja, qualquer objeto que implemente a interface IEnumerable). Por exemplo, se você tivesse uma matriz de contas, em vez de escrever uma lista C # para cada:

decimal total = 0; foreach (Account account in myAccounts) { if (account.Status == 'active') { total += account.Balance; } }

você poderia apenas escrever:

decimal total = (from account in myAccounts where account.Status == 'active' select account.Balance).Sum();

Embora este seja um exemplo bastante simples de como evitar esse problema comum de programação C #, há casos em que uma única instrução LINQ pode facilmente substituir dezenas de instruções em um loop iterativo (ou loops aninhados) em seu código. E menos código geral significa menos oportunidades para a introdução de bugs. Lembre-se, no entanto, de que pode haver uma compensação em termos de desempenho. Em cenários de desempenho crítico, especialmente onde seu código iterativo é capaz de fazer suposições sobre sua coleção que LINQ não pode, certifique-se de fazer uma comparação de desempenho entre os dois métodos.

Erro comum de programação em C # 5: deixar de considerar os objetos subjacentes em uma instrução LINQ

LINQ é excelente para abstrair a tarefa de manipulação de coleções, sejam elas objetos na memória, tabelas de banco de dados ou documentos XML. Em um mundo perfeito, você não precisaria saber quais são os objetos subjacentes. Mas o erro aqui é assumir que vivemos em um mundo perfeito. Na verdade, instruções LINQ idênticas podem retornar resultados diferentes quando executadas nos mesmos dados, se esses dados estiverem em um formato diferente.

Por exemplo, considere a seguinte declaração:

decimal total = (from account in myAccounts where account.Status == 'active' select account.Balance).Sum();

O que acontece se um dos objetos account.Status é igual a “Ativo” (observe o A maiúsculo)? Bem, se myAccounts era um DbSet (que foi configurado com a configuração padrão que não diferencia maiúsculas de minúsculas), o where expressão ainda corresponderia a esse elemento. No entanto, se myAccounts estava em uma matriz na memória, não corresponderia e, portanto, produziria um resultado diferente para o total.

Mas espere um minuto. Quando falamos sobre a comparação de strings anteriormente, vimos que == operador realizou uma comparação ordinal de strings. Então, por que neste caso o == operador realizando uma comparação sem distinção entre maiúsculas e minúsculas?

A resposta é que, quando os objetos subjacentes em uma instrução LINQ são referências aos dados da tabela SQL (como é o caso do objeto DbSet do Entity Framework neste exemplo), a instrução é convertida em uma instrução T-SQL. Os operadores então seguem as regras de programação T-SQL, não as regras de programação C #, portanto, a comparação no caso acima acaba sendo insensível a maiúsculas e minúsculas.

Em geral, embora LINQ seja uma maneira útil e consistente de consultar coleções de objetos, na realidade você ainda precisa saber se sua instrução será ou não traduzida para algo diferente de C # nos bastidores para garantir que o comportamento de seu código ser o esperado em tempo de execução.

Erro comum de programação em C # 6: ficar confuso ou falsificado por métodos de extensão

Conforme mencionado anteriormente, as instruções LINQ funcionam em qualquer objeto que implemente IEnumerable. Por exemplo, a seguinte função simples adicionará os saldos de qualquer coleção de contas:

public decimal SumAccounts(IEnumerable myAccounts) { return myAccounts.Sum(a => a.Balance); }

No código acima, o tipo do parâmetro myAccounts é declarado como IEnumerable. Desde myAccounts referências a Sum método (C # usa a conhecida “notação de ponto” para fazer referência a um método em uma classe ou interface), esperaríamos ver um método chamado Sum() sobre a definição de IEnumerable interface. No entanto, a definição de IEnumerable, não faz referência a qualquer Sum método e simplesmente se parece com isto:

public interface IEnumerable : IEnumerable { IEnumerator GetEnumerator(); }

Então, onde está o Sum() método definido? C # é fortemente tipado, portanto, se a referência a Sum método era inválido, o compilador C # certamente o sinalizaria como um erro. Portanto, sabemos que ele deve existir, mas onde? Além disso, onde estão as definições de todos os outros métodos fornecidos pelo LINQ para consultar ou agregar essas coleções?

A resposta é que Sum() não é um método definido no IEnumerable interface. Em vez disso, é um método estático (denominado “método de extensão”) que é definido no System.Linq.Enumerable classe:

namespace System.Linq { public static class Enumerable { ... // the reference here to “this IEnumerable source” is // the magic sauce that provides access to the extension method Sum public static decimal Sum(this IEnumerable source, Func selector); ... } }

Então, o que torna um método de extensão diferente de qualquer outro método estático e o que nos permite acessá-lo em outras classes?

A característica distintiva de um método de extensão é o this modificador em seu primeiro parâmetro. Esta é a “mágica” que o identifica para o compilador como um método de extensão. O tipo de parâmetro que ele modifica (neste caso IEnumerable) denota a classe ou interface que aparecerá para implementar este método.

(Como um ponto lateral, não há nada mágico sobre a semelhança entre o nome da interface IEnumerable e o nome da Enumerable classe na qual o método de extensão é definido. Essa semelhança é apenas uma escolha estilística arbitrária .)

Com esse entendimento, também podemos ver que o sumAccounts função que apresentamos acima poderia ter sido implementada da seguinte forma:

public decimal SumAccounts(IEnumerable myAccounts) { return Enumerable.Sum(myAccounts, a => a.Balance); }

O fato de que poderíamos ter implementado dessa forma levanta a questão de por que existem métodos de extensão? Métodos de extensão são essencialmente uma conveniência da linguagem de programação C # que permite “adicionar” métodos a tipos existentes sem criar um novo tipo derivado, recompilar ou modificar o tipo original.

Os métodos de extensão são trazidos ao escopo incluindo um using [namespace]; declaração na parte superior do arquivo. Você precisa saber qual namespace C # inclui os métodos de extensão que você está procurando, mas isso é muito fácil de determinar quando você sabe o que está procurando.

Quando o compilador C # encontra uma chamada de método em uma instância de um objeto e não encontra esse método definido na classe de objeto referenciada, ele examina todos os métodos de extensão que estão dentro do escopo para tentar encontrar um que corresponda ao método necessário assinatura e classe. Se encontrar um, ele passará a referência de instância como o primeiro argumento para aquele método de extensão, então o resto dos argumentos, se houver, serão passados ​​como argumentos subsequentes para o método de extensão. (Se o compilador C # não encontrar nenhum método de extensão correspondente dentro do escopo, ele gerará um erro.)

Os métodos de extensão são um exemplo de “açúcar sintático” por parte do compilador C #, o que nos permite escrever um código que é (geralmente) mais claro e mais fácil de manter. Mais claro, isto é, se você estiver ciente de seu uso. Caso contrário, pode ser um pouco confuso, especialmente no início.

Embora certamente haja vantagens em usar métodos de extensão, eles podem causar problemas e uma necessidade de ajuda na programação C # para os desenvolvedores que não estão cientes deles ou não os entendem adequadamente. Isso é especialmente verdadeiro ao examinar amostras de código online ou qualquer outro código pré-escrito. Quando esse código produz erros de compilador (porque ele invoca métodos que claramente não estão definidos nas classes em que são invocados), a tendência é pensar que o código se aplica a uma versão diferente da biblioteca, ou a uma biblioteca completamente diferente. Muito tempo pode ser gasto procurando por uma nova versão, ou 'biblioteca ausente' fantasma, que não existe.

Mesmo os desenvolvedores que estão familiarizados com métodos de extensão ainda são pegos ocasionalmente, quando há um método com o mesmo nome no objeto, mas sua assinatura de método difere sutilmente daquela do método de extensão. Muito tempo pode ser perdido procurando um erro de digitação ou erro que simplesmente não existe.

O uso de métodos de extensão em bibliotecas C # está se tornando cada vez mais predominante. Além do LINQ, o Bloco de Aplicativos Unity e a Estrutura de API da Web são exemplos de duas bibliotecas modernas muito usadas pela Microsoft que também usam métodos de extensão, e há muitos outros. Quanto mais moderna for a estrutura, mais provável será que ela incorpore métodos de extensão.

Claro, você também pode escrever seus próprios métodos de extensão. Perceba, entretanto, que embora os métodos de extensão pareçam ser invocados como os métodos de instância regulares, isso é realmente apenas uma ilusão. Em particular, seus métodos de extensão não podem fazer referência a membros privados ou protegidos da classe que eles estão estendendo e, portanto, não podem servir como um substituto completo para a herança de classe mais tradicional.

Erro comum de programação em C # 7: usar o tipo errado de coleção para a tarefa em questão

C # fornece uma grande variedade de objetos de coleção, sendo o seguinte apenas uma lista parcial:
Array, ArrayList, BitArray, BitVector32, Dictionary, HashTable, HybridDictionary, List, NameValueCollection, OrderedDictionary, Queue, Queue, SortedList, Stack, Stack, StringCollection, StringDictionary.

Embora possa haver casos em que muitas escolhas são tão ruins quanto escolhas insuficientes, esse não é o caso com objetos de coleção. O número de opções disponíveis pode definitivamente funcionar a seu favor. Dedique um pouco mais de tempo para pesquisar e escolher o tipo de coleção ideal para sua finalidade. Provavelmente resultará em melhor desempenho e menos espaço para erros.

Se houver um tipo de coleção voltado especificamente para o tipo de elemento que você tem (como uma corda ou broca), tente usá-lo primeiro. A implementação geralmente é mais eficiente quando é direcionada a um tipo específico de elemento.

Para tirar vantagem da segurança de tipo do C #, você geralmente deve preferir uma interface genérica em vez de uma não genérica. Os elementos de uma interface genérica são do tipo que você especifica ao declarar seu objeto, enquanto os elementos de interfaces não genéricas são do tipo objeto. Ao usar uma interface não genérica, o compilador C # não pode verificar o tipo de seu código. Além disso, ao lidar com coleções de tipos de valores primitivos, o uso de uma coleção não genérica resultará em boxing / unboxing desses tipos, o que pode resultar em um impacto negativo significativo no desempenho quando comparado a uma coleção genérica do tipo apropriado.

Outro problema comum do C # é escrever seu próprio objeto de coleção. Isso não quer dizer que nunca seja apropriado, mas com uma seleção tão abrangente quanto a que o .NET oferece, você provavelmente pode economizar muito tempo usando ou estendendo uma que já existe, em vez de reinventar a roda. Em particular, a C5 Generic Collection Library para C # e CLI oferece uma ampla gama de coleções adicionais “prontas para usar”, como estruturas de dados de árvore persistentes, filas de prioridade baseadas em heap, listas de array indexadas por hash, listas vinculadas e muito mais.

Erro comum de programação em C # 8: Negligenciar recursos livres

O ambiente CLR emprega um coletor de lixo, então você não precisa liberar explicitamente a memória criada para qualquer objeto. Na verdade, você não pode. Não há equivalente do C ++ delete ou o free() função em C. Mas isso não significa que você pode simplesmente esquecer todos os objetos depois de usá-los. Muitos tipos de objetos encapsulam algum outro tipo de recurso do sistema (por exemplo, um arquivo de disco, conexão de banco de dados, soquete de rede, etc.). Deixar esses recursos abertos pode esgotar rapidamente o número total de recursos do sistema, degradando o desempenho e, por fim, levando a falhas do programa.

Embora um método destruidor possa ser definido em qualquer classe C #, o problema com destruidores (também chamados de finalizadores em C #) é que você não pode saber com certeza quando eles serão chamados. Eles são chamados pelo coletor de lixo (em um encadeamento separado, o que pode causar complicações adicionais) em um momento indeterminado no futuro. Tentar contornar essas limitações forçando a coleta de lixo com GC.Collect() não é um Prática recomendada C # , pois isso bloqueará o encadeamento por um período de tempo desconhecido enquanto ele coleta todos os objetos elegíveis para coleta.

Isso não quer dizer que não haja bons usos para finalizadores, mas liberar recursos de forma determinística não é um deles. Em vez disso, quando você está operando em um arquivo, rede ou conexão de banco de dados, deseja liberar explicitamente o recurso subjacente assim que terminar de usá-lo.

Vazamentos de recursos são uma preocupação em quase qualquer ambiente . No entanto, o C # fornece um mecanismo robusto e simples de usar que, se utilizado, pode tornar os vazamentos uma ocorrência muito mais rara. A estrutura .NET define o IDisposable interface, que consiste apenas em Dispose() método. Qualquer objeto que implemente IDisposable espera ter esse método chamado sempre que o consumidor do objeto terminar de manipulá-lo. Isso resulta na liberação explícita e determinística de recursos.

Se você estiver criando e descartando um objeto dentro do contexto de um único bloco de código, é basicamente indesculpável esquecer de chamar Dispose(), porque C # fornece um using declaração que irá garantir Dispose() é chamado independentemente de como o bloco de código é encerrado (seja uma exceção, uma instrução de retorno ou simplesmente o fechamento do bloco). E sim, é o mesmo using declaração mencionada anteriormente que é usada para incluir namespaces C # na parte superior do seu arquivo. Ele tem um segundo propósito, completamente não relacionado, do qual muitos desenvolvedores C # desconhecem; ou seja, para garantir que Dispose() é chamado em um objeto quando o bloco de código é encerrado:

using (FileStream myFile = File.OpenRead('foo.txt')) { myFile.Read(buffer, 0, 100); }

Ao criar um bloco using no exemplo acima, você tem certeza de que myFile.Dispose() será chamado assim que você terminar de usar o arquivo, seja Read() lança uma exceção.

Erro comum de programação C # 9: evitando exceções

C # continua sua aplicação de segurança de tipo no tempo de execução. Isso permite que você identifique muitos tipos de erros em C # muito mais rapidamente do que em linguagens como C ++, onde conversões de tipo com defeito podem resultar em valores arbitrários sendo atribuídos aos campos de um objeto. No entanto, mais uma vez, os programadores podem desperdiçar esse ótimo recurso, levando a problemas de C #. Eles caem nessa armadilha porque o C # oferece duas maneiras diferentes de fazer as coisas, uma que pode gerar uma exceção e outra que não. Alguns fugirão da rota de exceção, imaginando que não ter que escrever um bloco try / catch os poupa algum código.

Por exemplo, aqui estão duas maneiras diferentes de realizar uma conversão de tipo explícito em C #:

// METHOD 1: // Throws an exception if account can't be cast to SavingsAccount SavingsAccount savingsAccount = (SavingsAccount)account; // METHOD 2: // Does NOT throw an exception if account can't be cast to // SavingsAccount; will just set savingsAccount to null instead SavingsAccount savingsAccount = account as SavingsAccount;

O erro mais óbvio que poderia ocorrer com o uso do Método 2 seria uma falha em verificar o valor de retorno. Isso provavelmente resultaria em uma eventual NullReferenceException, que possivelmente poderia surgir em um momento muito posterior, tornando muito mais difícil rastrear a origem do problema. Em contraste, o Método 1 teria gerado imediatamente um InvalidCastException tornando a origem do problema muito mais óbvia.

Além disso, mesmo que você se lembre de verificar o valor de retorno no Método 2, o que fará se achar que ele é nulo? O método que você está escrevendo é um local apropriado para relatar um erro? Existe algo mais que você pode tentar se o elenco falhar? Caso contrário, lançar uma exceção é a coisa correta a fazer, portanto, você também pode deixar que aconteça o mais próximo possível da origem do problema.

Aqui estão alguns exemplos de outros pares comuns de métodos em que um lança uma exceção e o outro não:

int.Parse(); // throws exception if argument can’t be parsed int.TryParse(); // returns a bool to denote whether parse succeeded IEnumerable.First(); // throws exception if sequence is empty IEnumerable.FirstOrDefault(); // returns null/default value if sequence is empty

Alguns desenvolvedores C # são tão “adversos a exceções” que assumem automaticamente que o método que não lança uma exceção é superior. Embora existam alguns casos selecionados em que isso possa ser verdade, não é de todo correto como generalização.

Como um exemplo específico, em um caso em que você tem uma ação alternativa legítima (por exemplo, padrão) a ser executada se uma exceção tivesse sido gerada, a abordagem de não exceção poderia ser uma escolha legítima. Nesse caso, pode realmente ser melhor escrever algo assim:

if (int.TryParse(myString, out myInt)) { // use myInt } else { // use default value }

em vez de:

try { myInt = int.Parse(myString); // use myInt } catch (FormatException) { // use default value }

No entanto, é incorreto presumir que TryParse é, portanto, necessariamente o método “melhor”. Às vezes é esse o caso, às vezes não. É por isso que existem duas maneiras de fazer isso. Use o correto para o contexto em que você está, lembrando que as exceções certamente podem ser suas amigas como desenvolvedor.

Erro comum de programação em C # 10: Permitir que avisos do compilador se acumulem

Embora esse problema definitivamente não seja específico do C #, ele é particularmente notório na programação C #, uma vez que abandona os benefícios da verificação de tipo estrita oferecida pelo compilador C #.

Os avisos são gerados por um motivo. Embora todos os erros do compilador C # representem um defeito em seu código, muitos avisos também significam. O que diferencia os dois é que, no caso de um aviso, o compilador não tem problemas em emitir as instruções que seu código representa. Mesmo assim, ele considera seu código um pouco suspeito e há uma probabilidade razoável de que seu código não reflita com precisão sua intenção.

Um exemplo simples comum para o propósito deste tutorial de programação C # é quando você modifica seu algoritmo para eliminar o uso de uma variável que estava usando, mas se esquece de remover a declaração da variável. O programa será executado perfeitamente, mas o compilador sinalizará a declaração da variável inútil. O fato de o programa funcionar perfeitamente faz com que os programadores negligenciem a correção da causa do aviso. Além disso, os codificadores tiram proveito de um recurso do Visual Studio que facilita a ocultação dos avisos na janela “Lista de erros” para que possam se concentrar apenas nos erros. Não demora muito até que haja dezenas de avisos, todos eles alegremente ignorados (ou ainda pior, ocultos).

Mas se você ignorar esse tipo de aviso, mais cedo ou mais tarde, algo como isso pode muito bem entrar em seu código:

class Account { int myId; int Id; // compiler warned you about this, but you didn’t listen! // Constructor Account(int id) { this.myId = Id; // OOPS! } }

E na velocidade que o Intellisense nos permite escrever código, esse erro não é tão improvável quanto parece.

Agora você tem um erro sério em seu programa (embora o compilador o tenha sinalizado apenas como um aviso, pelos motivos já explicados) e, dependendo de quão complexo é seu programa, você pode perder muito tempo rastreando este. Se você tivesse prestado atenção a esse aviso em primeiro lugar, teria evitado esse problema com uma correção simples de cinco segundos.

Lembre-se de que o compilador C Sharp oferece muitas informações úteis sobre a robustez do seu código ... se você estiver ouvindo. Não ignore os avisos. Geralmente, eles levam apenas alguns segundos para serem corrigidos, e corrigir novos quando eles acontecem pode economizar horas. Treine-se para esperar que a janela “Lista de erros” do Visual Studio exiba “0 erros, 0 avisos”, de modo que quaisquer avisos o deixem desconfortável o suficiente para resolvê-los imediatamente.

Claro, existem exceções a todas as regras. Da mesma forma, pode haver momentos em que seu código parecerá um pouco duvidoso para o compilador, mesmo que seja exatamente como você pretendia que fosse. Nesses casos muito raros, use #pragma warning disable [warning id] em torno apenas do código que dispara o aviso e apenas do ID de aviso que ele dispara. Isso suprimirá aquele aviso, e apenas aquele aviso, para que você ainda possa ficar alerta para novos.

Embrulhar

C # é uma linguagem poderosa e flexível com muitos mecanismos e paradigmas que podem melhorar muito a produtividade. No entanto, como acontece com qualquer ferramenta de software ou linguagem, ter uma compreensão limitada ou apreciação de seus recursos pode às vezes ser mais um impedimento do que um benefício, deixando alguém no estado proverbial de “saber o suficiente para ser perigoso”.

Usando um tutorial C Sharp como este para familiarizar-se com as nuances principais do C #, como (mas de forma alguma se limitando a) os problemas levantados neste artigo, ajudará na otimização do C # enquanto evita algumas das armadilhas mais comuns da linguagem.

barreiras para comunicação intercultural
Relacionado: 6 perguntas essenciais da entrevista C #

Compreender o básico

O que é C #?

C # é uma das várias linguagens de programação voltadas para o Microsoft CLR, que oferece automaticamente os benefícios de integração entre linguagens e tratamento de exceções, segurança aprimorada, um modelo simplificado para interação de componentes e serviços de depuração e criação de perfil.

Qual é a diferença entre C ++ e C #?

C ++ e C # são duas linguagens completamente diferentes, apesar das semelhanças no nome e na sintaxe. C # foi projetado para ter um nível um pouco mais alto do que C ++, e as duas linguagens também adotam abordagens diferentes para detalhes, como quem determina se um parâmetro é passado por referência ou por valor.

Por que o C # é usado?

C # é usado por muitos motivos, mas os benefícios do conjunto de ferramentas Microsoft CLR e uma grande comunidade de desenvolvedores são dois atrativos principais para a linguagem.

Folha de dicas de CSS rápida e prática do ApeeScape

Web Front-End

Folha de dicas de CSS rápida e prática do ApeeScape
Carlos Slim recebeu uma impressão positiva de Donald Trump sobre o México na reunião: porta-voz

Carlos Slim recebeu uma impressão positiva de Donald Trump sobre o México na reunião: porta-voz

Mundo

Publicações Populares
As crianças estão passando mais 'tempo sozinhos' com os pais. O que isso significa?
As crianças estão passando mais 'tempo sozinhos' com os pais. O que isso significa?
Um tutorial de fluxo de trabalho de design para desenvolvedores: entregue melhor UI / UX no prazo
Um tutorial de fluxo de trabalho de design para desenvolvedores: entregue melhor UI / UX no prazo
Aprimore o fluxo do usuário - um guia para análise de UX
Aprimore o fluxo do usuário - um guia para análise de UX
Trabalhos a serem realizados: Transforme as necessidades do cliente em soluções de produtos
Trabalhos a serem realizados: Transforme as necessidades do cliente em soluções de produtos
O presidente dos EUA, Donald Trump, critica a ex-NSA Susan Rice por desmascarar funcionários
O presidente dos EUA, Donald Trump, critica a ex-NSA Susan Rice por desmascarar funcionários
 
Todos Juntos Agora - Uma Visão Geral do Design Inclusivo
Todos Juntos Agora - Uma Visão Geral do Design Inclusivo
Métodos de pesquisa UX e o caminho para a empatia do usuário
Métodos de pesquisa UX e o caminho para a empatia do usuário
Como o GWT desbloqueia a realidade aumentada em seu navegador
Como o GWT desbloqueia a realidade aumentada em seu navegador
Um guia para codificação UTF-8 em PHP e MySQL
Um guia para codificação UTF-8 em PHP e MySQL
O que Force Touch significa para IU e UX?
O que Force Touch significa para IU e UX?
Publicações Populares
  • ferramentas de visualização de dados como tableau
  • uma curva de demanda é construída com base no pressuposto de que
  • o que cfo significa nos negócios
  • como fazer uma linguagem de programação em java
  • estrutura da pasta do projeto do aplicativo do windows forms
Categorias
  • Ágil
  • Américas
  • Processos Financeiros
  • Design Ux
  • © 2022 | Todos Os Direitos Reservados

    portaldacalheta.pt