雷达智富

首页 > 内容 > 程序笔记 > 正文

程序笔记

Linq to Object的Where和Select实现原理

2024-10-15 11

Linq的Where是一个基于委托的代码封装,把数据筛选的通用逻辑完成,把判断逻辑交给委托传递。Select是基于委托的代码封装,把数据转换的通用逻辑完成,把转换逻辑交给委托传递。

Linq还有很多方法,这些方法大多都是基于委托的代码封装,也有一些是不需要委托的,例如Sum。

实现方法是把通用逻辑写好,把可变逻辑当成委托传递。

namespace MyStudy
{
    public static class LinqExtension
    {
        /// <summary>
        /// 与官方Where一样,迭代器返回Ienumerable,按需获取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tList"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> tList, Func<T, bool> func) {
            foreach (var t in tList) {
                if (func.Invoke(t)) {
                    yield return t;
                }
            }
        }
        /// <summary>
        /// 也能实现Where功能,一次性返回结果集
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tList"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static List<T> MyWhereList<T>(this List<T> tList, Func<T, bool> func) {
            List<T> result = new List<T>();
            foreach (var t in tList) {
                if (func.Invoke(t)) {
                    result.Add(t);
                }
            }
            return result;
        }
        public static IEnumerable<T1> MySelect<T, T1>(this IEnumerable<T> tList, Func<T, T1> func) {
            foreach (var t in tList) {
                yield return func.Invoke(t);
            }
        }
    }
}

代码中yield return是语法糖,返回Ienumerable结果集时,编译器会生成很多代码,是一个迭代器,能够实现数据按需加载。

Console测试运行代码

namespace MyStudy
{
    class Program
    {
        static void Main(string[] args)
        {
            var testEntities = new List<TestEntity>() {
                new TestEntity(){
                    Id = 1,
                    Name="Name1",
                    Age=18
                },
                new TestEntity(){
                    Id = 2,
                    Name="Name2",
                    Age=11
                },
                new TestEntity(){
                    Id = 3,
                    Name="Name3",
                    Age=19
                }
            };
            var list1 = testEntities.MyWhere(x => x.Id > 1);
            foreach (var item in list1) {
                Console.WriteLine(item.Name);
            }
            var list2 = testEntities.Where(x => x.Id > 1);
            foreach (var item in list1)
            {
                Console.WriteLine(item.Name);
            }
            var list3 = testEntities.MySelect(x => new { Id = x.Id, Name = x.Name });
            foreach (var item in list3)
            {
                Console.WriteLine(item.Name);
            }
            var list4 = testEntities.Select(x => new { Id = x.Id, Name = x.Name });
            foreach (var item in list4)
            {
                Console.WriteLine(item.Name);
            }
            //分解写法
            Func<TestEntity, bool> func = new Func<TestEntity, bool>(t => t.Id > 1);
            var list5 = testEntities.Where(func);
            foreach (var item in list5)
            {
                Console.WriteLine(item.Name);
            }
            Console.ReadLine();
        }
    }
}

Linq to Object和Linq to Sql的区别:

Linq to Object 数据源是内存里的集合,传递的是委托。

Linq to Sql 数据源来自数据库,传递的是lanmbda表达式目录树(Expression<Func<TSource,bool>>),解析表达式转化成Sql语句。

更新于:3天前
赞一波!

文章评论

评论问答