在C#中为LINQ查询添加自定义方法
通过为IEnumerable接口引入扩展方法,你可以扩展用于LINQ查询的方法集。例如,你可以通过在SQL Server中创建你的自定义聚合方法将任何数据序列转换成一个值。
你也可以建立一个方法,返回一个新的数值系列,并作为一个自定义过滤器或一个专门的数据转换,用于变量序列。
为LINQ查询添加自定义方法(C#)
简介
一些例子包括Distinct和Skip技术,以及Reverse技术。
当你扩展IEnumerable接口时,你可以将你的方法应用于任何可枚举的集合。在这篇文章中,我们将看看C#中用于LINQ查询的各种自定义方法。
添加一个聚合方法
当一组数值被聚合时,可以生成一个单一的数值。平均值、最小值和最大值只是LINQ中可用的几种聚合技术。通过向IEnumerable接口引入一个扩展方法,你可以设计你的聚合方法。
中位数是一个扩展方法,它可以计算出一串双值数的中位数。
public static class LINQExtensionExample
{
public static double Median(this IEnumerable<double>? source)
{
if (!(source?.Any() ?? false))
{
throw a new InvalidOperationException("A null or empty set cannot be used to compute the median..");
}
var sortedList = (from numberX in source
orderby numberX
select numberX).ToList();
int itemIndex = sortedList.Count / 2;
if (sortedList.Count % 2 == 0)
{
// Rerurning an even number of objects or items
return (sortedList[itemIndex] + sortedList[itemIndex - 1]) / 2;
}
else
{
// Rerurning an odd number of objects or items
return sortedList[itemIndex];
}
}
}
从IEnumerable接口调用这个扩展方法和调用其他聚合函数没有任何区别。
在一个双数组上,下面的代码演示了使用中位数方法。
double[] numbers1 = { 0.9, 5, 2, 9.3, 2.6, 7, 3.3, 4 };
var query = numbers1.Median();
Console.WriteLine("double: Median = " + query1);
/*
The output of the above code is as shown below
Double: Median = 5.95
*/
一个聚合方法通过接受各种类型而被重载
为了接受不同类型的序列,你可以重载你的聚合方法。重载每个类型是典型的技术。然而,也可以使用一个委托来为一个通用类型建立重载。将这两种方法结合起来也是一种选择。
建立一个类型重载
我们可以为我们想要支持的每一种类型创建一个单独的重载。这里有一个Median方法的int类型重载,你可以在下面的代码例子中看到。
//Overload of int
public static double Median(this IEnumerable<int> source) =>
(from numX in source select (double)numX).Median();
With the new Median overloads available for both integer and double types, the following code shows how to use them:
double[] numbers2 = { 0.9, 5, 2, 9.3, 2.6, 7, 3.3, 4};
var query2 = numbers2.Median();
Console.WriteLine("double: Median = " + query2);
int[] numbers3 = { 14, 16, 15, 13, 11, 10, 9 };
var query3 = numbers3.Median();
Console.WriteLine("int: Median = " + query3);
/*
Here's what it looks like when it runs:
The Double part: Median = 5.95
The Integer part: Median = 13
*/
启动一个泛型溢出
如果你想这么做,也可以用一个泛型对象的列表作为重载的输入。在这个重载中,Delegate是作为一个变量提供的,它使用Delegate将泛型对象转换为一个特定的类型。
下面的代码显示了Median的Func T, TResult委托的一个重载。一个通用类型T的对象被传递给这个委托,它返回一个双倍类型的对象作为结果。
// Let us take a look
public static double Median<T>(this IEnumerable<T> numbersY,
Func<T, double> selector) =>
(from num in numbersY select selector(num)).Median();
当处理任何类型的对象序列时,你现在可以使用中值技术。如果该类型没有其重载的过程,我们必须传入一个委托参数。C#中的Lambda表达式可用于此目的。使用Aggregate或Group By子句来代替方法调用,只有在Visual Basic中才是真的。
你可以使用下面的代码在一个字符串数组和一个整数数组上调用Median方法。使用一个字符串数组,为数组中每个字符串的长度得出一个中值。
在代码中的每个场景都使用Median方法的委托参数。在每个使用该方法的场景中,为FuncT, TResult使用Median方法的委托参数。
int[] numbers4 = { 14, 16, 15, 13, 11, 10, 9 };
/*
In this case, the compiler will implicitly convert num=>num's value to double when you pass it as a parameter to the Median method.
Otherwise, the compiler will give the user an error message.
*/
var query4 = numbers4.Median(num => num);
Console.WriteLine("int: Median = " + query3);
string[] numbers5 = { "fourteen", "sixteen", "fifteen", "thirteen", "eleven", "ten", "nine" };
// A number of object properties are available with the generic overload.
var query5 = numbers5.Median(str => str.Length);
Console.WriteLine("String: Median = " + query5);
/*
Here's what it looks like when it runs:
Integer: Median = 13
String: Median = 13
*/
添加一个返回序列的方法
IENumerableT可以用自定义的查询方法进行扩展,以返回一个序列的值。在这种情况下必须返回一个IEnumerableT的集合。使用这些方法可以将过滤器或数据转换应用到一个值的序列。
使用AlternateElements扩展方法,可以返回一个集合中的每一个其他元素,从第一个元素开始。
//The IEnumerableT> interface has an extension method.
// Every other element in a sequence is returned by the method.
public static IEnumerable<T> AlternateElements<T>(this IEnumerable<T> source)
{
int y = 3;
foreach (var element in source)
{
if (y % 2 == 1)
{
yield return element;
}
y++;
}
}
这个函数可以用来扩展任何可枚举的集合。
string[] strings = { "u", "v", "w", "x" };
var query4 = strings.AlternateElements();
foreach (var element in query6)
{
Console.WriteLine(element);
}
/*
Here's what it looks like when it runs:
u
w
*/
作为一个实际的例子,让我们看一下下面的例子。这个例子使用JSON来序列化一些数据库。然后用JArray.Parse将存储一些数据,之后我们再将JSON应用于LINQ查询来读取数据。
using System;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace JSON_LINQ_TOJSON
{
class ProgramExample
{
static void Main(string[] args)
{
// Here you are going to get the data in JSON serialized form
string WorkersData = JsonConvert.SerializeObject(new WorkersDatabase(),Formatting.Indented);
// This will convert the JSON string into an array
JArray workersArray = JArray.Parse(WorkersData);
// The total number of workers is read
var resWorkers = (from w in workersArray
select w["WorkersName"]).ToList();
Console.WriteLine("Only Workers Names");
foreach (var item in resWorkers)
{
Console.WriteLine(item.Value<string>().ToString());
}
// Then one will get the work or the Job details
Console.WriteLine();
var result = (from w in workersArray.Workers()["Job"]
select w).ToList();
Console.WriteLine("Job Details");
foreach (var item in result.Wokers().ToList())
{
Console.WriteLine(item.ToObject<Job>().JobId + "\t" + item.ToObject<Job>().JobType);
}
Console.ReadLine();
}
}
}
总结
我们已经看到我们如何在我们的C#应用程序中利用LINQ查询。开发一个从API中检索JSON数据的应用程序,使用LINQ查询来查询数据。