文章目录
前言
本文章是本人对Linq与委托的一些理解,不对的地方还望指正
文章在说Linq之前会先说明委托,因为委托是组成Linq的一部分
假如有以下代码 需要筛选分数>=60的对象 你会怎么做
/// <summary>
/// 测试
/// </summary>
public void Test()
{
List<Student> students = new List<Student>();
Random random = new Random();
for (int i = 0; i < 100; i++)
{
students.Add(new Student
{
Name = i.ToString(),
Sex = random.Next(0, 2),
Mark = random.Next(0, 101),
});
}
}
public class Student
{
/// <summary>
/// 名字
/// </summary>
public string Name { get; set; }
/// <summary>
/// 性别 0 男 1 女
/// </summary>
public int Sex { get; set; }
/// <summary>
/// 分数
/// </summary>
public int Mark { get; set; }
}
在使用Linq的做法是
var IEList = students.Where(t => t.Mark >= 60);
一、什么是delegate(委托) ?
委托是将方法包装成参数传递到其他地方执行的工具
1.委托的定义
下面代码块中定义了一些委托与方法
/// <summary>
/// 定义无参,无返回值的 委托
/// </summary>
delegate void Delegate1();
/// <summary>
/// 定义1个参数,无返回值的 委托
/// </summary>
delegate void Delegate2(string val1);
/// <summary>
/// 定义2个参数,无返回值的 委托
/// </summary>
delegate void Delegate3(string val1, string val2);
/// <summary>
/// 定义无参,返回int值的 委托
/// </summary>
delegate int Delegate4();
/// <summary>
/// 定义无参,无返回值的 方法
/// </summary>
private void Method1()
{
Console.WriteLine("我是无参 无返回值 方法");
}
/// <summary>
/// 定义1个参数,无返回值的 方法
/// </summary>
/// <param name="val1"></param>
private void Method2(string val1)
{
Console.WriteLine("我是有1个参数 无返回值 方法");
}
/// <summary>
/// 定义2个参数,无返回值的 方法
/// </summary>
/// <param name="val1"></param>
/// <param name="val2"></param>
private void Method3(string val1, string val2)
{
Console.WriteLine("我是有2个参数 无返回值 方法");
}
/// <summary>
/// 定义无参,返回int值的 方法
/// </summary>
/// <returns></returns>
private int Method4()
{
Console.WriteLine("我是无参 无返回值 方法");
return 0;
}
2.使用自定义委托
/// <summary>
/// 测试委托
/// </summary>
public void TestDelegate()
{
//委托的各种写法
Delegate1 delegate1_1 = new Delegate1(() => { });//匿名
Delegate1 delegate1_2 = () => { };//匿名
Delegate1 delegate1_3 = new Delegate1(Method1);
Delegate1 delegate1_4 = Method1;
//当委托只有一行代码时,可以去掉{}
Delegate1 delegate1_5 = () => Console.WriteLine("111");//匿名
Delegate2 delegate2_1 = new Delegate2((val1) => { });//匿名
Delegate2 delegate2_2 = (val1) => { };//匿名
Delegate2 delegate2_3 = new Delegate2(Method2);
Delegate2 delegate2_4 = Method2;
//当委托只有一个参数时 参数两边的括号可以去掉
Delegate2 delegate2_5 = new Delegate2(val1 => { });//匿名
Delegate2 delegate2_6 = val1 => { };//匿名
Delegate3 delegate3_1 = new Delegate3((val1, val2) => { });//匿名
Delegate3 delegate3_2 = (val1, val2) => { };//匿名
Delegate3 delegate3_3 = new Delegate3(Method3);
Delegate3 delegate3_4 = Method3;
Delegate4 delegate4_1 = new Delegate4(() => { return 1; });//匿名
Delegate4 delegate4_2 = () => { return 1; };//匿名
Delegate4 delegate4_3 = new Delegate4(Method4);
Delegate4 delegate4_4 = Method4;
//当委托只有一行代码时,可以去掉{},如果是有返回值 则 需要忽略掉return
Delegate4 delegate4_5 = new Delegate4(() => 1);//匿名
Delegate4 delegate4_6 = () => 1;//匿名
}
3.匿名委托独有特性
匿名委托独有特性 匿名委托类可以直接访问方法类的参数
public void TestDelegate()
{
//匿名委托独有特性 匿名委托类可以直接访问方法类的参数
int test = 123;
Delegate1 delegate1_5 = () =>
{
//访问 委托外面的test参数
Console.WriteLine(test);
};
}
4.如何触发委托中的方法
匿名委托独有特性 匿名委托类可以直接访问方法类的参数
public void TestDelegate()
{
//匿名委托独有特性 匿名委托类可以直接访问方法类的参数
int test = 123;
Delegate1 delegate1_5 = () =>
{
//访问 委托外面的test参数
Console.WriteLine(test);
};
delegate1_5();//方式1
delegate1_5.Invoke();//方式2
}
4.Action与Func
一般情况下不建议使用自定义委托
因为 .Net里面已经有了现成的委托
Action与Func
Action是无返回值的委托,而且Action与泛型进行了结合 并且有很多重载
Func是具有返回值的委托,而且Func与泛型进行了结合 并且有很多重载
大部分情况下使用这两个委托就可以了
使用这两个委托的最大好处
比如有两个委托
delegate void Delegate1();
delegate void Delegate2();
Delegate1 delegate1 = () => Console.WriteLine(“111”);
Delegate2 delegate2 = () => Console.WriteLine(“111”);
以下代码中 就只能传递delegate1 而无法传递delegate2
虽然他们都是无参无返回值委托
public void TestDelegate(Delegate1 delegate1)
{
delegate1();
}
如果都使用Action则不会存在上述问题
Func同理
5.将自定义委托改为Action与Func的写法
/// <summary>
/// 测试
/// </summary>
public void TestDelegate()
{
Action delegate1_1 = new Action(() => { });//匿名
Action delegate1_2 = () => { };//匿名
Action delegate1_3 = new Action(Method1);
Action delegate1_4 = Method1;
//当委托只有一行代码时,可以去掉{}
Action delegate1_5 = () => Console.WriteLine("111");//匿名
Action<string> delegate2_1 = new Action<string>((val1) => { });//匿名
Action<string> delegate2_2 = (val1) => { };//匿名
Action<string> delegate2_3 = new Action<string>(Method2);
Action<string> delegate2_4 = Method2;
//当委托只有一个参数时 参数两边的括号可以去掉
Action<string> delegate2_5 = new Action<string>(val1 => { });//匿名
Action<string> delegate2_6 = val1 => { };//匿名
Action<string,string> delegate3_1 = new Action<string, string>((val1, val2) => { });//匿名
Action<string, string> delegate3_2 = (val1, val2) => { };//匿名
Action<string, string> delegate3_3 = new Action<string, string>(Method3);
Action<string, string> delegate3_4 = Method3;
Func<int> delegate4_1 = new Func<int>(() => { return 1; });//匿名
Func<int> delegate4_2 = () => { return 1; };//匿名
Func<int> delegate4_3 = new Func<int>(Method4);
Func<int> delegate4_4 = Method4;
//当委托只有一行代码时,可以去掉{},如果是有返回值 则 需要忽略掉return
Func<int> delegate4_5 = new Func<int>(() => 1);//匿名
Func<int> delegate4_6 = () => 1;//匿名
}
二、Linq的组成 ?
Linq由 扩展方法、迭代、委托、泛型 组合而成的
1.各种方法的定义
public class MethodClass
{
/// <summary>
/// 普通方法长这样
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="ResultT"></typeparam>
/// <param name="list">普通 参数1</param>
/// <param name="func">转换委托</param>
/// <returns></returns>
public List<ResultT> Method1<T, ResultT>(IEnumerable<T> list, Func<T, ResultT> func)
{
List<ResultT> reslut = new List<ResultT>();
foreach (var item in list)
{
reslut.Add(func(item));
}
return reslut;
}
/// <summary>
/// 静态 普通方法长这样
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="ResultT"></typeparam>
/// <param name="list">普通 参数1</param>
/// <param name="func">转换委托</param>
/// <returns></returns>
public static List<ResultT> Method2<T, ResultT>(IEnumerable<T> list, Func<T, ResultT> func)
{
List<ResultT> reslut = new List<ResultT>();
foreach (var item in list)
{
reslut.Add(func(item));
}
return reslut;
}
/// <summary>
/// 静态 迭代方法长这样
/// 迭代方法与普通方法的区别在于 迭代方法 只有实际需要结果时才会执行里面方法内逻辑 而 普通方法会马上执行方法内逻辑
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="ResultT"></typeparam>
/// <param name="list">普通 参数1</param>
/// <param name="func">转换委托</param>
/// <returns></returns>
public static IEnumerable<ResultT> Method3<T, ResultT>(IEnumerable<T> list, Func<T, ResultT> func)
{
//在迭代方法中 yield break; 表示结束迭代
//在迭代方法中 yield return 表示返回一次结果
foreach (var item in list)
{
yield return func(item);
}
}
}
在定义扩展方法时尽量不要使用 object 以及 没有约束的泛型 这样会导致所有类型都产生一个扩展方法
public static class MethodClass2
{
/// <summary>
/// 扩展方法长这样
/// 在定义扩展方法时尽量不要使用 object 以及 没有约束的泛型 这样会导致所有类型都产生一个扩展方法
/// </summary>
/// <param name="text">扩展的类型</param>
public static void Method1(this string text)
{
Console.WriteLine(text);
}
}
2.Linq方法的定义
比如linq里面的Select与Where,假如自己写的可以像下面这么写
public static class Linq2
{
/// <summary>
/// 结合上面的扩展方法 迭代 以及委托 泛型 即可组成Linq
/// 示例 Select
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="ResultT"></typeparam>
/// <param name="list">扩展参数</param>
/// <param name="func">转换委托</param>
/// <returns></returns>
public static IEnumerable<ResultT> Select2<T, ResultT>(this IEnumerable<T> list, Func<T, ResultT> func)
{
//在迭代方法中 yield break; 表示结束迭代
//在迭代方法中 yield return 表示返回一次结果
foreach (var item in list)
{
yield return func(item);
}
}
/// <summary>
/// 结合上面的扩展方法 迭代 以及委托 泛型 即可组成Linq
/// 示例 Where
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">扩展参数</param>
/// <param name="func">指示如何保留内容的委托</param>
/// <returns></returns>
public static IEnumerable<T> Where2<T>(this IEnumerable<T> list, Func<T, bool> func)
{
//在迭代方法中 yield break; 表示结束迭代
//在迭代方法中 yield return 表示返回一次结果
foreach (var item in list)
{
if (func(item))
{
yield return item;
}
}
}
}
总结
再回到最初的问题
需要筛选分数>=60的对象 你会怎么做
通过调试不难发现这两个方法得到的结果是一样的
而代码中的t => t.Mark >= 60则是匿名委托Func< Student,bool>
由于只有一个参数 可以省略t左右两边的()
由于只有一行代码则可以将{ return t.Mark >= 60; } 写成 t.Mark >= 60
var IEList = students.Where(t => t.Mark >= 60);
var IEList2 = students.Where2(t => t.Mark >= 60);