C#Linq与delegate(委托)


前言

本文章是本人对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);
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值