Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Todos os métodos baseados em LINQ seguem um de dois padrões semelhantes. Eles utilizam uma sequência enumerável. Eles devolvem ou uma sequência diferente ou um único valor. A consistência da forma permite estender o LINQ escrevendo métodos com uma forma semelhante. Na verdade, as bibliotecas .NET ganharam novos métodos em muitas versões do .NET desde que o LINQ foi introduzido pela primeira vez. Neste artigo, você verá exemplos de extensão do LINQ escrevendo seus próprios métodos que seguem o mesmo padrão.
Adicionar métodos personalizados para consultas LINQ
Expanda o conjunto de métodos que utiliza para consultas LINQ adicionando métodos de extensão à IEnumerable<T> interface. Por exemplo, além das operações médias ou máximas padrão, você cria um método de agregação personalizado para calcular um único valor a partir de uma sequência de valores. Você também cria um método que funciona como um filtro personalizado ou uma transformação de dados específica para uma sequência de valores e retorna uma nova sequência. Exemplos de tais métodos são Distinct, Skip, e Reverse.
Ao estender a IEnumerable<T> interface, você pode aplicar seus métodos personalizados a qualquer coleção enumerável. Para obter mais informações, consulte Membros de extensão.
Um método agregado calcula um único valor a partir de um conjunto de valores. O LINQ fornece vários métodos agregados, incluindo Average, Mine Max. Crie o seu próprio método de agregado adicionando um método de extensão à IEnumerable<T> interface.
A partir do C# 14, você pode declarar um bloco de extensão para conter vários membros de extensão. Declare um bloco de extensão com a palavra-chave extension seguida do parâmetro receptor entre parênteses. O exemplo de código a seguir mostra como criar um método de extensão chamado Median em um bloco de extensão. O método calcula uma mediana para uma sequência de números do tipo double.
extension(IEnumerable<double>? source)
{
public double Median()
{
if (source is null || !source.Any())
{
throw new InvalidOperationException("Cannot compute median for a null or empty set.");
}
var sortedList =
source.OrderBy(number => number).ToList();
int itemIndex = sortedList.Count / 2;
if (sortedList.Count % 2 == 0)
{
// Even number of items.
return (sortedList[itemIndex] + sortedList[itemIndex - 1]) / 2;
}
else
{
// Odd number of items.
return sortedList[itemIndex];
}
}
}
Você também pode adicionar o this modificador a um método estático para declarar um método de extensão. O código a seguir mostra o método de extensão equivalente Median :
public static class EnumerableExtension
{
public static double Median(this IEnumerable<double>? source)
{
if (source is null || !source.Any())
{
throw new InvalidOperationException("Cannot compute median for a null or empty set.");
}
var sortedList =
source.OrderBy(number => number).ToList();
int itemIndex = sortedList.Count / 2;
if (sortedList.Count % 2 == 0)
{
// Even number of items.
return (sortedList[itemIndex] + sortedList[itemIndex - 1]) / 2;
}
else
{
// Odd number of items.
return sortedList[itemIndex];
}
}
}
Chame qualquer um dos métodos de extensão para qualquer coleção enumerável da mesma forma que chama outros métodos agregados a partir da IEnumerable<T> interface.
O exemplo de código a seguir mostra como usar o Median método para uma matriz do tipo double.
double[] numbers = [1.9, 2, 8, 4, 5.7, 6, 7.2, 0];
var query = numbers.Median();
Console.WriteLine($"double: Median = {query}");
// This code produces the following output:
// double: Median = 4.85
Sobrecarregue o seu método agregado para que aceite sequências de vários tipos. A abordagem padrão é criar uma sobrecarga para cada tipo. Outra abordagem é criar uma sobrecarga que usa um tipo genérico e convertê-lo em um tipo específico usando um delegado. Você também pode combinar ambas as abordagens.
Cria uma sobrecarga específica para cada tipo que queres suportar. O exemplo de código a seguir mostra uma sobrecarga do Median método para o int tipo.
// int overload
public static double Median(this IEnumerable<int> source) =>
(from number in source select (double)number).Median();
Agora pode chamar as Median sobrecargas para ambos os tipos integer e double, conforme mostrado no código a seguir:
double[] numbers1 = [1.9, 2, 8, 4, 5.7, 6, 7.2, 0];
var query1 = numbers1.Median();
Console.WriteLine($"double: Median = {query1}");
int[] numbers2 = [1, 2, 3, 4, 5];
var query2 = numbers2.Median();
Console.WriteLine($"int: Median = {query2}");
// This code produces the following output:
// double: Median = 4.85
// int: Median = 3
Você também pode criar uma sobrecarga que aceita uma sequência genérica de objetos. Essa sobrecarga usa um delegado como parâmetro e o usa para converter uma sequência de objetos de um tipo genérico em um tipo específico.
O código a seguir mostra uma sobrecarga do método Median que recebe o delegado Func<T,TResult> como parâmetro. Este delegado pega um objeto do tipo genérico T e retorna um objeto do tipo double.
// generic overload
public static double Median<T>(
this IEnumerable<T> numbers, Func<T, double> selector) =>
(from num in numbers select selector(num)).Median();
Agora você pode chamar o Median método para uma sequência de objetos de qualquer tipo. Se o tipo não tiver a sua própria sobrecarga de métodos, passe um parâmetro delegado. Em C#, você pode usar uma expressão lambda para essa finalidade. Além disso, apenas no Visual Basic, se usares a Aggregate cláusula ou Group By em vez da chamada de método, podes passar qualquer valor ou expressão que esteja no âmbito desta cláusula.
O código de exemplo a seguir mostra como chamar o Median método para uma matriz de inteiros e uma matriz de cadeias de caracteres. Para cadeias de caracteres, é calculada a mediana dos comprimentos das cadeias de caracteres na matriz. O exemplo mostra como passar o Func<T,TResult> parâmetro delegate para o Median método para cada caso.
int[] numbers3 = [1, 2, 3, 4, 5];
/*
You can use the num => num lambda expression as a parameter for the Median method
so that the compiler will implicitly convert its value to double.
If there is no implicit conversion, the compiler will display an error message.
*/
var query3 = numbers3.Median(num => num);
Console.WriteLine($"int: Median = {query3}");
string[] numbers4 = ["one", "two", "three", "four", "five"];
// With the generic overload, you can also use numeric properties of objects.
var query4 = numbers4.Median(str => str.Length);
Console.WriteLine($"string: Median = {query4}");
// This code produces the following output:
// int: Median = 3
// string: Median = 4
Estenda a IEnumerable<T> interface com um método de consulta personalizado que devolve uma sequência de valores. Nesse caso, o método deve retornar uma coleção do tipo IEnumerable<T>. Tais métodos podem ser usados para aplicar filtros ou transformações de dados a uma sequência de valores.
O exemplo a seguir mostra como criar um método de extensão chamado AlternateElements que retorna todos os outros elementos em uma coleção, começando a partir do primeiro elemento.
// Extension method for the IEnumerable<T> interface.
// The method returns every other element of a sequence.
public static IEnumerable<T> AlternateElements<T>(this IEnumerable<T> source)
{
int index = 0;
foreach (T element in source)
{
if (index % 2 == 0)
{
yield return element;
}
index++;
}
}
Chame este método de extensão para qualquer coleção enumerável, tal como chamaria outros métodos da IEnumerable<T> interface, como mostrado no seguinte código:
string[] strings = ["a", "b", "c", "d", "e"];
var query5 = strings.AlternateElements();
foreach (var element in query5)
{
Console.WriteLine(element);
}
// This code produces the following output:
// a
// c
// e
Cada exemplo mostrado neste artigo tem um recetor diferente. Isto significa que deve declarar cada método num bloco de extensão diferente que especifica o recetor único. O exemplo de código a seguir mostra uma única classe estática com três blocos de extensão diferentes, cada um dos quais contém um dos métodos definidos neste artigo:
public static class EnumerableExtension
{
extension(IEnumerable<double>? source)
{
public double Median()
{
if (source is null || !source.Any())
{
throw new InvalidOperationException("Cannot compute median for a null or empty set.");
}
var sortedList =
source.OrderBy(number => number).ToList();
int itemIndex = sortedList.Count / 2;
if (sortedList.Count % 2 == 0)
{
// Even number of items.
return (sortedList[itemIndex] + sortedList[itemIndex - 1]) / 2;
}
else
{
// Odd number of items.
return sortedList[itemIndex];
}
}
}
extension(IEnumerable<int> source)
{
public double Median() =>
(from number in source select (double)number).Median();
}
extension<T>(IEnumerable<T> source)
{
public double Median(Func<T, double> selector) =>
(from num in source select selector(num)).Median();
public IEnumerable<T> AlternateElements()
{
int index = 0;
foreach (T element in source)
{
if (index % 2 == 0)
{
yield return element;
}
index++;
}
}
}
}
O bloco de extensão final declara um bloco de extensão genérico. O parâmetro de tipo para o recetor é declarado no próprio extension.
O exemplo anterior declara um membro de extensão em cada bloco de extensão. Na maioria dos casos, você cria vários membros de extensão para o mesmo recetor. Nesses casos, declare as extensões desses membros num único bloco de extensão.