0Pricing
C# Academy · Aula

Projetando boas extensões

Aplique boas práticas e evite armadilhas.

Projetando boas extensões é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.

Projetando extensões que as pessoas adoram

Os métodos de extensão são poderosos, mas esse poder pode levar ao uso indevido. Boas extensões parecem uma parte natural do tipo, são fáceis de descobrir e nunca surpreendem quem as chama. Esta lição aborda diretrizes práticas.

Estenda o comportamento, não a identidade

Prefira extensões para comportamentos utilitários que sejam fáceis de ler em um fluxo. Se um método realmente pertencer a um tipo que você possui, torne-o um membro real.

using System;

public static class TimeExtensions
{
    // A pleasant, focused helper
    public static bool IsWeekend(this DayOfWeek day)
        => day == DayOfWeek.Saturday || day == DayOfWeek.Sunday;
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(DayOfWeek.Sunday.IsWeekend());
        Console.WriteLine(DayOfWeek.Monday.IsWeekend());
    }
}

Mantenha os métodos puros quando possível

Extensões que retornam um novo valor e evitam efeitos colaterais são mais fáceis de entender e encadear. Procure receber uma entrada e devolver um valor.

using System;

public static class StringExtensions
{
    // Pure: depends only on input, returns a new string
    public static string Truncate(this string s, int max)
        => s.Length <= max ? s : s.Substring(0, max) + "...";
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Extension methods are great".Truncate(10));
    }
}

Proteja-se contra entradas nulas

Como os chamadores podem invocar uma extensão em um receptor null, decida deliberadamente o que deve acontecer. Tolere nulos de forma adequada ou lance uma ArgumentNullException clara.

using System;

public static class StringExtensions
{
    public static string SafeUpper(this string s)
    {
        if (s is null) throw new ArgumentNullException(nameof(s));
        return s.ToUpper();
    }
}

public class Program
{
    public static void Main()
    {
        try { ((string)null).SafeUpper(); }
        catch (ArgumentNullException ex) { Console.WriteLine("Caught: " + ex.ParamName); }
        Console.WriteLine("ok".SafeUpper());
    }
}

Dê nomes que facilitem a descoberta

Os desenvolvedores encontram extensões digitando o ponto e examinando o IntelliSense. Nomes claros, baseados em verbos e que descrevam o resultado tornam seus auxiliares fáceis de descobrir e autoexplicativos.

using System;
using System.Collections.Generic;

public static class CollectionExtensions
{
    public static bool HasItems<T>(this ICollection<T> c)
        => c != null && c.Count > 0;
}

public class Program
{
    public static void Main()
    {
        var list = new List<int> { 1 };
        Console.WriteLine(list.HasItems());
    }
}

Agrupe extensões relacionadas de forma coesa

Coloque as extensões de um mesmo conceito em uma classe estática e em um espaço de nomes com nomes claros. Isso mantém as importações significativas e permite que os usuários tragam exatamente os auxiliares que desejam.

using System;
using System.Collections.Generic;

public static class EnumerableExtensions
{
    public static IEnumerable<T> TakeFirst<T>(this IEnumerable<T> source, int n)
    {
        int taken = 0;
        foreach (var item in source)
        {
            if (taken++ >= n) yield break;
            yield return item;
        }
    }
}

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 1, 2, 3, 4 };
        Console.WriteLine(string.Join(",", nums.TakeFirst(2)));
    }
}

Não oculte comportamentos surpreendentes

Uma extensão que parece simples, mas executa um trabalho caro ou mantém estado, viola as expectativas. Torne o custo evidente; se ela consultar um banco de dados ou modificar o estado, dê-lhe um nome que indique isso.

using System;

public static class MathExtensions
{
    // Cheap and obvious: no hidden cost
    public static int ClampMin(this int value, int min)
        => value < min ? min : value;
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine((-3).ClampMin(0));
        Console.WriteLine(5.ClampMin(0));
    }
}

Evite estender object

Estender object polui todos os tipos do programa com seu método, deixando o IntelliSense desorganizado em toda parte. Em vez disso, direcione-o ao tipo ou à interface mais específica que faça sentido.

using System;

public static class IntExtensions
{
    // Specific to int, not object - far less noisy
    public static string ToOrdinal(this int n)
    {
        if (n % 10 == 1 && n % 100 != 11) return n + "st";
        if (n % 10 == 2 && n % 100 != 12) return n + "nd";
        if (n % 10 == 3 && n % 100 != 13) return n + "rd";
        return n + "th";
    }
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine(1.ToOrdinal());
        Console.WriteLine(22.ToOrdinal());
    }
}

Prefira retornar IEnumerable para sequências

Para operadores de sequência, retorne IEnumerable<T> e use a execução adiada. Isso permite uma boa composição e evita obrigar os chamadores a materializar dados de que talvez não precisem.

using System;
using System.Collections.Generic;

public static class SeqExtensions
{
    public static IEnumerable<int> Doubled(this IEnumerable<int> source)
    {
        foreach (var n in source) yield return n * 2;
    }
}

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 1, 2, 3 };
        foreach (var n in nums.Doubled()) Console.WriteLine(n);
    }
}

Uma lista de verificação para boas extensões

Antes de publicar uma extensão, pergunte: o nome é claro? Ela é pura ou seus efeitos colaterais são evidentes? Os valores nulos são tratados? O tipo-alvo é específico? Ela está agrupada de forma sensata? Se a resposta for sim para tudo, você terá um auxiliar que outras pessoas gostarão de usar.

using System;

public static class StringExtensions
{
    public static string OrDefault(this string s, string fallback)
        => string.IsNullOrEmpty(s) ? fallback : s;
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine("".OrDefault("N/A"));
        Console.WriteLine("value".OrDefault("N/A"));
    }
}

Experimente

Aplique a lista de verificação: um tipo-alvo específico, um nome claro, tolerância a valores nulos e um resultado puro. Esta pequena extensão segue todas as diretrizes.

using System;
using System.Collections.Generic;

public static class DictionaryExtensions
{
    // Clear name, specific type, null-safe, pure
    public static TValue GetOrDefault<TKey, TValue>(
        this IReadOnlyDictionary<TKey, TValue> dict, TKey key, TValue fallback)
    {
        if (dict == null) return fallback;
        return dict.TryGetValue(key, out var value) ? value : fallback;
    }
}

public class Program
{
    public static void Main()
    {
        var ages = new Dictionary<string, int> { ["Ann"] = 30 };
        Console.WriteLine(ages.GetOrDefault("Ann", -1));
        Console.WriteLine(ages.GetOrDefault("Bob", -1));
    }
}

Verificação rápida

Aplique as diretrizes de projeto.

Recapitulação

Extensões bem projetadas parecem nativas e previsíveis.

  • Prefira auxiliares puros que retornem valores e possam ser bem encadeados.
  • Decida e documente o comportamento para valores nulos.
  • Use nomes claros, baseados em verbos, para facilitar a descoberta.
  • Direcione-os a tipos ou interfaces específicos, não a object.
  • Agrupe auxiliares relacionados e retorne IEnumerable<T> para sequências.

Perguntas Frequentes

A aula “Projetando boas extensões” é grátis?

Sim — o texto completo de “Projetando boas extensões” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.

O que vou aprender em “Projetando boas extensões”?

Aplique boas práticas e evite armadilhas. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar C# Academy?

Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Projetando boas extensões”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de C# Academy?

Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Definindo métodos de extensão
  2. Estendendo interfaces e genéricos
  3. Resolução de métodos de extensão
  4. Projetando boas extensões
← Voltar para C# Academy