Estendendo interfaces e genéricos
Adicione comportamento a vários tipos de uma só vez.
Estendendo interfaces e genéricos é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 2 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.
Estendendo interfaces
Você pode escrever um método de extensão cujo parâmetro this seja uma interface. Todo tipo que implementa a interface passa imediatamente a ter esse método. É exatamente assim que o LINQ adiciona dezenas de métodos a IEnumerable<T>.
Uma extensão genérica em IEnumerable
Ao tornar o método genérico sobre T e estender IEnumerable<T>, o auxiliar funciona com qualquer sequência: listas, vetores, resultados de consultas e muito mais.
using System;
using System.Collections.Generic;
public static class EnumerableExtensions
{
public static bool IsEmpty<T>(this IEnumerable<T> source)
{
foreach (var item in source) return false;
return true;
}
}
public class Program
{
public static void Main()
{
var nums = new List<int> { 1, 2, 3 };
Console.WriteLine(nums.IsEmpty());
Console.WriteLine(new int[0].IsEmpty());
}
}Iterando a sequência
Dentro da extensão, trate o parâmetro como qualquer IEnumerable<T>. Aqui, calculamos uma soma sem depender do LINQ.
using System;
using System.Collections.Generic;
public static class EnumerableExtensions
{
public static int SumValues(this IEnumerable<int> source)
{
int total = 0;
foreach (var n in source) total += n;
return total;
}
}
public class Program
{
public static void Main()
{
var nums = new List<int> { 10, 20, 30 };
Console.WriteLine(nums.SumValues());
}
}Retornando uma nova sequência
As extensões também podem retornar sequências. Combinadas com yield return, elas se tornam operadores no estilo do LINQ com avaliação tardia.
using System;
using System.Collections.Generic;
public static class EnumerableExtensions
{
public static IEnumerable<T> EveryOther<T>(this IEnumerable<T> source)
{
bool take = true;
foreach (var item in source)
{
if (take) yield return item;
take = !take;
}
}
}
public class Program
{
public static void Main()
{
var letters = new List<string> { "a", "b", "c", "d", "e" };
foreach (var l in letters.EveryOther())
Console.WriteLine(l);
}
}Restrições de tipos genéricos
Você pode restringir o parâmetro genérico para exigir determinados recursos. Aqui, where T : IComparable<T> permite comparar itens para encontrar um máximo.
using System;
using System.Collections.Generic;
public static class EnumerableExtensions
{
public static T MaxItem<T>(this IEnumerable<T> source) where T : IComparable<T>
{
bool started = false;
T best = default;
foreach (var item in source)
{
if (!started || item.CompareTo(best) > 0) { best = item; started = true; }
}
return best;
}
}
public class Program
{
public static void Main()
{
var nums = new List<int> { 3, 9, 1, 7 };
Console.WriteLine(nums.MaxItem());
}
}Estendendo uma interface personalizada
Suas próprias interfaces também se beneficiam. Defina uma interface e anexe comportamentos compartilhados por meio de extensões, em vez de duplicá-los em cada implementação.
using System;
public interface INamed { string Name { get; } }
public class Dog : INamed { public string Name => "Rex"; }
public static class NamedExtensions
{
public static string Greeting(this INamed n) => "Hello, " + n.Name;
}
public class Program
{
public static void Main()
{
var d = new Dog();
Console.WriteLine(d.Greeting());
}
}Vários parâmetros de tipo
As extensões podem ser genéricas em relação a vários parâmetros de tipo. Este auxiliar de projeção transforma uma sequência usando uma função, de forma muito parecida com o Select do LINQ.
using System;
using System.Collections.Generic;
public static class EnumerableExtensions
{
public static IEnumerable<TResult> Map<TSource, TResult>(
this IEnumerable<TSource> source, Func<TSource, TResult> f)
{
foreach (var item in source) yield return f(item);
}
}
public class Program
{
public static void Main()
{
var nums = new List<int> { 1, 2, 3 };
foreach (var s in nums.Map(n => "#" + n))
Console.WriteLine(s);
}
}Combinando com o LINQ integrado
Seus métodos de extensão coexistem com o LINQ. Você pode encadear seu operador personalizado com operadores padrão em um único fluxo encadeado.
using System;
using System.Collections.Generic;
using System.Linq;
public static class EnumerableExtensions
{
public static IEnumerable<T> EveryOther<T>(this IEnumerable<T> source)
{
bool take = true;
foreach (var item in source) { if (take) yield return item; take = !take; }
}
}
public class Program
{
public static void Main()
{
var nums = Enumerable.Range(1, 10);
var result = nums.Where(n => n > 2).EveryOther().ToList();
Console.WriteLine(string.Join(", ", result));
}
}Estender IEnumerable alcança muitos tipos
Como vetores, listas, dicionários, conjuntos de dispersão e resultados de consultas implementam IEnumerable<T>, uma única extensão abrange todos eles de uma só vez.
using System;
using System.Collections.Generic;
public static class EnumerableExtensions
{
public static int CountItems<T>(this IEnumerable<T> source)
{
int n = 0;
foreach (var item in source) n++;
return n;
}
}
public class Program
{
public static void Main()
{
Console.WriteLine(new[] { 1, 2, 3 }.CountItems());
Console.WriteLine(new HashSet<string> { "a", "b" }.CountItems());
}
}Por que este padrão é escalável
As extensões de interfaces fornecem auxiliares polimórficos sem herança. Escreva a lógica uma vez usando a interface, e toda implementação, atual ou futura, a obterá automaticamente.
using System;
using System.Collections.Generic;
public static class EnumerableExtensions
{
public static string JoinWith<T>(this IEnumerable<T> source, string sep)
{
return string.Join(sep, source);
}
}
public class Program
{
public static void Main()
{
var nums = new List<int> { 1, 2, 3 };
Console.WriteLine(nums.JoinWith(" -> "));
}
}Experimente
Crie um pequeno operador genérico em IEnumerable<T> e encadeie-o com o LINQ. Observe como ele funciona com qualquer tipo de sequência.
using System;
using System.Collections.Generic;
using System.Linq;
public static class EnumerableExtensions
{
public static IEnumerable<T> WithoutDuplicatesByKey<T, TKey>(
this IEnumerable<T> source, Func<T, TKey> keySelector)
{
var seen = new HashSet<TKey>();
foreach (var item in source)
if (seen.Add(keySelector(item))) yield return item;
}
}
public class Program
{
public static void Main()
{
var words = new[] { "apple", "avocado", "banana", "cherry", "blueberry" };
var firstPerLetter = words.WithoutDuplicatesByKey(w => w[0]);
Console.WriteLine(string.Join(", ", firstPerLetter));
}
}Verificação rápida
Pense em como as extensões no estilo do LINQ são declaradas.
Recapitulação
Estender interfaces, especialmente IEnumerable<T>, é a base da programação no estilo do LINQ.
- Torne o método genérico e use a interface como o tipo
this. - Use
yield returnpara criar operadores com avaliação tardia. - Aplique restrições
wherepara exigir recursos comoIComparable<T>. - Uma única extensão de interface abrange todas as implementações, inclusive as futuras.
Perguntas Frequentes
A aula “Estendendo interfaces e genéricos” é grátis?
Sim — o texto completo de “Estendendo interfaces e genéricos” é 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 “Estendendo interfaces e genéricos”?
Adicione comportamento a vários tipos de uma só vez. 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 2 de 4.
Quanto tempo leva a aula “Estendendo interfaces e genéricos”?
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
- Definindo métodos de extensão
- Estendendo interfaces e genéricos
- Resolução de métodos de extensão
- Projetando boas extensões