0Pricing
C# Academy · Aula

Utilitários genéricos reutilizáveis

Crie pequenos auxiliares reutilizáveis: verificações de proteção, um comparador de igualdade baseado em chaves, memoização para funções puras e um Result simples.

Utilitários genéricos reutilizáveis é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 3 de 3. 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 3 aulas no total.

Plano do kit de ferramentas

Objetivo: reunir pequenos auxiliares que possam ser reutilizados em vários projetos.

  • Verificações de Guard para argumentos
  • Comparador baseado em chave para igualdade
  • Memoize de uma função pura
  • Result<T> para o fluxo de sucesso e erro

Verificações de guarda

Centralize a validação de argumentos em uma pequena classe Guard; chame-a no início do método.

using System;

public static class Guard
{
  public static T NotNull<T>(T value, string name) where T : class
  {
    if (value == null) throw new ArgumentNullException(name);
    return value;
  }

  public static string NotNullOrEmpty(string value, string name)
  {
    if (string.IsNullOrEmpty(value)) throw new ArgumentException("must not be null or empty", name);
    return value;
  }
}

public class Program
{
  public static void Main(string[] args)
  {
    // OK
    string name = Guard.NotNullOrEmpty("Ada", "name");
    Console.WriteLine("Hello, " + name);

    // Uncomment to see guard throw:
    // Guard.NotNull<string>(null, "input");
  }
}

Comparador baseado em chave

Compare objetos complexos por uma chave, por exemplo, Id, sem alterar Equals/GetHashCode do modelo.

using System;
using System.Collections.Generic;

public sealed class KeyEqualityComparer<T, TKey> : IEqualityComparer<T>
{
  private readonly Func<T, TKey> _keySelector;
  private readonly IEqualityComparer<TKey> _keyComparer;

  public KeyEqualityComparer(Func<T, TKey> keySelector)
    : this(keySelector, EqualityComparer<TKey>.Default) {}

  public KeyEqualityComparer(Func<T, TKey> keySelector, IEqualityComparer<TKey> keyComparer)
  {
    if (keySelector == null) throw new ArgumentNullException("keySelector");
    if (keyComparer == null) throw new ArgumentNullException("keyComparer");
    _keySelector = keySelector;
    _keyComparer = keyComparer;
  }

  public bool Equals(T x, T y)
  {
    if (object.ReferenceEquals(x, y)) return true;
    if ((object)x == null || (object)y == null) return false;
    return _keyComparer.Equals(_keySelector(x), _keySelector(y));
  }

  public int GetHashCode(T obj)
  {
    if ((object)obj == null) return 0;
    TKey key = _keySelector(obj);
    return key == null ? 0 : _keyComparer.GetHashCode(key);
  }
}

public sealed class User
{
  public int Id;
  public string Name;
}

public class Program
{
  public static void Main(string[] args)
  {
    List<User> list = new List<User>();
    list.Add(new User { Id = 1, Name = "Ada" });
    list.Add(new User { Id = 1, Name = "Ada Lovelace" }); // same Id -> considered equal
    list.Add(new User { Id = 2, Name = "Alan" });

    // Deduplicate by Id using a HashSet with our comparer
    HashSet<User> set = new HashSet<User>(new KeyEqualityComparer<User,int>(delegate(User u) { return u.Id; }));
    foreach (User u in list) set.Add(u);

    Console.WriteLine("Unique by Id = " + set.Count); // 2
  }
}

Auxiliar de memoização

Memoize armazena em cache os resultados de uma função pura. Use-o em chamadas repetidas com a mesma entrada.

using System;
using System.Collections.Generic;

public static class Memo
{
  // Wrap a pure function f: K -> V with a simple cache
  public static Func<TKey, TValue> Memoize<TKey, TValue>(Func<TKey, TValue> f)
  {
    if (f == null) throw new ArgumentNullException("f");
    Dictionary<TKey, TValue> cache = new Dictionary<TKey, TValue>();
    return delegate(TKey key)
    {
      TValue v;
      if (cache.TryGetValue(key, out v)) return v;
      v = f(key);
      cache[key] = v;
      return v;
    };
  }
}

public class Program
{
  static int SlowSquare(int x)
  {
    // Simulate work
    System.Threading.Thread.Sleep(100);
    return x * x;
  }

  public static void Main(string[] args)
  {
    Func<int,int> fast = Memo.Memoize<int,int>(SlowSquare);

    var t1 = DateTime.UtcNow; Console.WriteLine(fast(12));
    var t2 = DateTime.UtcNow; Console.WriteLine(fast(12)); // from cache
    var dt1 = (t2 - t1).TotalMilliseconds;

    var t3 = DateTime.UtcNow; Console.WriteLine(fast(12)); // from cache again
    var t4 = DateTime.UtcNow; var dt2 = (t4 - t3).TotalMilliseconds;

    Console.WriteLine("First vs cached ms: " + dt1 + " / " + dt2);
  }
}

Contêiner Result<T>

Um tipo mínimo Result<T> torna o sucesso e o erro explícitos e fáceis de imprimir ou testar.

using System;

public enum ResultKind { Ok, Error }

public sealed class Result<T>
{
  public ResultKind Kind;
  public T Value;            // valid when Ok
  public string Error;       // valid when Error

  private Result() {}

  public static Result<T> Ok(T value)
  {
    Result<T> r = new Result<T>();
    r.Kind = ResultKind.Ok;
    r.Value = value;
    r.Error = null;
    return r;
  }

  public static Result<T> Fail(string error)
  {
    if (string.IsNullOrEmpty(error)) throw new ArgumentException("error");
    Result<T> r = new Result<T>();
    r.Kind = ResultKind.Error;
    r.Error = error;
    r.Value = default(T);
    return r;
  }

  public override string ToString()
  {
    return Kind == ResultKind.Ok ? "OK: " + (Value == null ? "null" : Value.ToString())
                                 : "ERROR: " + Error;
  }
}

public class Program
{
  static Result<int> ParsePositiveInt(string s)
  {
    int n;
    if (!Int32.TryParse(s, out n)) return Result<int>.Fail("not a number");
    if (n <= 0) return Result<int>.Fail("must be > 0");
    return Result<int>.Ok(n);
  }

  public static void Main(string[] args)
  {
    Console.WriteLine(ParsePositiveInt("12"));
    Console.WriteLine(ParsePositiveInt("-1"));
    Console.WriteLine(ParsePositiveInt("x"));
  }
}

Dicas práticas

Dicas:

  • Mantenha os auxiliares pequenos e focados.
  • Dê-lhes nomes claros: Guard, KeyEqualityComparer, Memo.
  • Documente as restrições e quando usar cada auxiliar, como funções puras para Memo.
  • Escreva um teste unitário rápido para cada auxiliar.

Benefício do comparador por chave

Verificação rápida: o que um IEqualityComparer baseado em chave permite fazer?

Recapitulação

Recapitulação: reutilize pequenas ferramentas — Guard para entradas, KeyEqualityComparer para igualdade, Memo para funções puras e Result<T> para resultados explícitos.

Perguntas Frequentes

A aula “Utilitários genéricos reutilizáveis” é grátis?

Sim — o texto completo de “Utilitários genéricos reutilizáveis” é 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 3 aulas no total.

O que vou aprender em “Utilitários genéricos reutilizáveis”?

Crie pequenos auxiliares reutilizáveis: verificações de proteção, um comparador de igualdade baseado em chaves, memoização para funções puras e um Result simples. 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 3 de 3.

Quanto tempo leva a aula “Utilitários genéricos reutilizáveis”?

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. unmanaged, notnull, new() (emulação no C# 6)
  2. Matemática genérica (visão geral), atributos genéricos (quando relevante)
  3. Utilitários genéricos reutilizáveis
← Voltar para C# Academy