Como desenvolvedor C#, aprender técnicas mais avançadas pode ajudar você a escrever um código mais limpo, mais eficiente e inovador. Neste artigo, exploraremos algumas dez dicas avançadas de C# personalizadas para desenvolvedores mais experientes que querem forçar os limites do que é possível em C#. Esses truques podem melhorar o desempenho, a legibilidade e a manutenibilidade do seu código.
Tradicionalmente, para retornar múltiplos valores de um método, os desenvolvedores tinham que usar parâmetros e criar classes ou estruturas personalizadas. O C# 7, no entanto, introduziu tuplas, o que torna mais fácil e legível fazer isso.
público ( int soma, int produto) Calcular( int a, int b)
{
return (a + b, a * b);
}
Essa abordagem simplifica o tratamento de múltiplos valores de retorno e melhora a clareza do código.
O C# 7 e versões posteriores introduziram recursos poderosos de correspondência de padrões que permitem verificações e conversões de tipos mais expressivas e concisas.
public void ProcessoForma ( objeto forma )
{
if (forma is Circulo c)
{
Console.WriteLine( $"Circulo com raio: {c.Raio} " );
}
else if (forma is Quadrado s)
{
Console.WriteLine( $"Quadrado com lado: {s.Lado} " );
}
}
Essa técnica reduz a quantidade de código clichê e torna o código mais fácil de ler.
No C# 7, funções locais foram introduzidas, o que permite que você defina métodos dentro de outro método. Essas funções são particularmente úteis para encapsular métodos auxiliares que só fazem sentido dentro de um método específico.
public IEnumerable Fibonacci(int n)
{
int Fib(int term) => term <= 2 ? 1 : Fib(term - 1) + Fib(term - 2);
return Enumerable.Range(1, n).Select(Fib);
}
Funções locais podem acessar variáveis do método envolvente, o que oferece uma maneira concisa de implementar lógica complexa.
Membros com corpo de expressão ajudam a tornar o código mais conciso, pois permitem a implementação de métodos, propriedades e outros membros em uma única linha de código.
public class Pessoa
{
public string Nome { get; set; }
public override string ToString() => $"Nome: {Nome}";
}
Esse recurso, que foi expandido em versões recentes do C#, facilita a definição de membros de classe leves.
Estruturas somente leitura são ideais para criar tipos de dados imutáveis. Isso significa que, uma vez que um objeto é criado, ele não pode ser alterado.
public readonly struct Ponto
{
public double A { get; }
public double B { get; }
public Ponto(double a, double b) => (A, B) = (a, b);
}
Essa construção é útil para representar tipos de dados pequenos e imutáveis, como coordenadas ou números complexos.
Os retornos de ref e os locais permitem que os métodos retornem referências a variáveis, em vez dos valores em si. Isso pode melhorar significativamente o desempenho para objetos grandes.
public ref int BuscarPor(int[] numbers, int target)
{
for (int i = 0; i < numbers.Length; i++)
{
if (numbers[i] == target)
return ref numbers[i];
}
throw new IndexOutOfRangeException("Nao Encontrado");
}
Esse recurso é especialmente útil em códigos sensíveis ao desempenho que manipulam grandes estruturas de dados.
Descartes são um recurso avançado que permite que os desenvolvedores ignorem parâmetros ou tuplas nos quais não estão interessados. Isso torna o código mais legível e fácil de manter.
var (_, produto) = Calcular(3, 4); // Interessado apenas no produto
Isso facilita o manuseio de métodos que retornam vários valores, pois você só precisa de alguns deles.
O operador de atribuição de coalescência nula ??=simplifica o processo de atribuição de valores a variáveis quando elas podem ser nulas.
List numeros = null;
numeros ??= new List();
numeros.Add(1);
Este operador reduz a quantidade de código necessária para garantir que um objeto seja criado antes de ser usado.
ValueTuple é uma alternativa leve à estrutura de dados Tuple, que oferece uma abordagem mais eficiente em termos de memória para gerenciar coleções de valores.
var pessoa = (Nome: "John", Idade: 30);
Console.WriteLine($"{pessoa.Nome} tem {pessoa.idade} anos de idade.");
ValueTuple é particularmente útil para estruturas de dados temporárias onde a sobrecarga de uma classe é desnecessária.
Os fluxos assíncronos, introduzidos no C# 8, permitem a implementação de iteração assíncrona sobre coleções que são carregadas assincronamente. Isso melhora significativamente o desempenho em aplicativos que processam dados de streaming ou são limitados por E/S.
public async IAsyncEnumerable PegaNumerosAsync()
{
for (int i = 0; i < 10; i++)
{
await Task.Delay(100); // Simula Trabalho Assíncrono.
yield return i;
}
}