c#linq

文章目录

    • 扩展方法
    • linq的简单演化
    • Linq To Object
      • 常见的使用示例
    • Linq To SQL
    • 总结

扩展方法

扩展方法的具体定义我就不写自行去搜索,我简单说一下扩展方法,定义一个扩展方法就在一个静态类中,定义一个静态方法,方法的第一个参数就是你需要扩展类型,之后你可以可以在这个类型的实例直接调用这个方法:
比如我们为string增加一个截断的如果超过多长就截取后面加…的扩展方法。

   public static class ExtendMethod
    {
     
     public static string ToLength(this string text, int length = 15)
        {
     
            if (string.IsNullOrWhiteSpace(text))
            {
     
                return "空";
            }
            else if (text.Length > length)
            {
     
                return ($"{text.Substring(0, length)}...");
            }
            else
            {
     
                return text;
            }
        }
    }
 public static int ToInt(this int? i)
        {
     
      

            return i ?? 0;
        }
                    int? k = 23;
                    int l = 4;
                    //int r = k??0 + l;
                    int r = k.ToInt() + l;和上行等同
  1. 扩展方法调用,很像实例方法,就像扩展了Student的逻辑
  2. 适合扩展第三方的类,不适合修改源码,可以通过扩展方法增加逻辑,优先调用实例方法,最怕扩展方法增加了,别人类又修改了
  3. 适合组件式开发的扩展(.NetCore),定义接口或者类,是按照最小需求,但是在开发的时候又经常需要一些方法,就通过扩展方法 context.Response.WriteAsync 中间件的注册
  4. 扩展方法也可以是泛型方法,但不要使用没有约束的泛型去扩展,这样的话T就相当于object了。会污染基础类型。
  public static string ToStringCustom<T>(this T t)
        {
     
            if (t is Guid)
            {
     
                return t.ToString().Replace("-", "");
            }
            //.....
            else
            {
     
                return t.ToString();
            }
        }

linq的简单演化

我们首先设想一个场景,比如我们有一个student数据集合,我们常规需要对student进行不懂的数据过滤做不通的安排,常规情况下的数据过滤,我们需要年龄小于30:

 				List<Student> studentList = this.GetStudentList();
 				//年纪小于30
                var list = new List<Student>();
                foreach (var item in studentList)
                {
     
                    if (item.Age < 30)
                    {
     
                        list.Add(item);
                    }
                }

或者我们需要Name长度大于2的

                //Name长度大于2的
                var list = new List<Student>();
                foreach (var item in studentList)
                {
     
                    if (item.Name.Length > 2)
                    {
     
                        list.Add(item);
                    }
                }

或者我们需要更多的条件:

//N个条件叠加
                    var list = new List<Student>();
                    foreach (var item in studentList)
                    {
     
                        if (item.Id > 1
                            && item.Name != null
                            && item.ClassId == 1
                            && item.Age > 20)
                        {
     
                            list.Add(item);
                        }
                    }

这样写是不是很麻烦,而且很不友好,不能有一个办法,我们只需要传过滤条件要实现,这样委托就派上用场了,我们通过委托来作为过滤条件,使用Func返回条件bool值来判断数据过滤,我们通过添加一个扩展方法来实现这个数据的过滤:

public static class ExtendMethod
{
     
	//泛型完成对不同类型的数据过滤
	public static List<T> ElevenWhere<T>(this List<T> resource, Func<T, bool> func)
        {
     
            var list = new List<T>();
            foreach (var item in resource)
            {
     
                if (func.Invoke(item))//通过委托带入数据过滤条件
                {
     
                    list.Add(item);
                }
            }
            return list;
        }
}

这样我们就可以这样来过滤数据了:

 	var result = studentList.ElevenWhere<Student>(s => s.Age < 30);
    var result = studentList.ElevenWhere(s => s.Name.Length > 2);
    var result = studentList.ElevenWhere(item => item.Id > 1
                                                            && item.Name != null
                                                            && item.ClassId == 1
                                                            && item.Age > 20);

等同上面数据过滤效果。这里面的委托使用的是lambda表达式,如果不清楚lambda表达式,参考上一章C#Lambda表达式
这不就是我们平时见到的linq的表达式,其实linq表达式实现的原理就是和上面一样
我们自定义的linq表达式返回的List而实际的linq都是IEnumerable,我们崽升级一下代码

public static IEnumerable<T> ElevenWhereIterator<T>(this IEnumerable<T> resource, Func<T, bool> func)
        {
     
         
            var list = new List<T>();
            foreach (var item in resource)
            {
     
                if (func.Invoke(item))
                {
     
                    list.Add(item);
                }
            }
            return list;
        }

再升级一下代码:

//迭代器模式,完成了数据的按需获取,延迟加载
 public static IEnumerable<T> ElevenWhereIterator<T>(this IEnumerable<T> resource, Func<T, bool> func)
        {
     
            foreach (var item in resource)
            {
     
                Console.WriteLine("进入数据检测");
                Thread.Sleep(100);
                if (func.Invoke(item))
                {
     
                    yield return item;//yield 跟IEnumerable配对使用
                }
            }
         }

我们使用了迭代器yield(这个以后详细讲一章)为什么使用可枚举类型IEnumerable,这个官方定义的可枚举类型,IEnumerable的介绍可以参考先说IEnumerable,我们每天用的foreach你真的懂它吗
到这里我们应该基本上明白linq是什么东西了。

Linq To Object

  1. 在Enumerable类,针对IEnumerable数据,指的是内存数据
  2. Where:把对数据过滤的通用操作完成,把可变的过滤逻辑交给委托
  3. Select:把对数据转化的通用操作完成,把可变的转换逻辑交给委托
  4. OrderBy…
  5. Linq 其实就是把对数据操作的通用部分完成,把可变的交给委托,使用者只用关心可变部分,其实Linq就是这么一个封装,但确实很好用

常见的使用示例

  //这里有一堆学生  每个学生都转换成别的对象

                Console.WriteLine("**********投影**********");
                //查询运算符方式
                var list = studentList.Where<Student>(s => s.Age < 30)
                                     .Select(s => new
                                     {
     
                                         IdName = s.Id + s.Name,
                                         ClassName = s.ClassId == 2 ? "高级班" : "其他班"
                                     });
//表达式方式
var list = from s in studentList
                           where s.Age < 30
                           select new
                           {
     
                               IdName = s.Id + s.Name,
                               ClassName = s.ClassId == 2 ? "高级班" : "其他班"
                           };

上面两种写法是等同效果。

 //IN查询
                var list = studentList.Where<Student>(s => s.Age < 30)
                    .Where(s => new int[] {
      1, 2, 3, 4 }.Contains(s.ClassId))
                                     .Select(s => new
                                     {
     
                                         IdName = s.Id + s.Name,
                                         ClassName = s.ClassId == 2 ? "高级班" : "其他班"
                                     });
 var list = studentList.Where<Student>(s => s.Age < 30)//条件过滤
                                     .Select(s => new//投影
                                     {
     
                                         Id = s.Id,
                                         ClassId = s.ClassId,
                                         IdName = s.Id + s.Name,
                                         ClassName = s.ClassId == 2 ? "高级班" : "其他班"
                                     })
                                     .OrderBy(s => s.Id)//排序
                                                        //.ThenBy//2个都生效
                                     .OrderByDescending(s => s.ClassId)//倒排  最后一个生效
                                     .Skip(2)//跳过几条
                                     .Take(3)//获取几条
                                     ;
  var list = from s in studentList
                           where s.Age < 30
                           group s by s.ClassId into sg
                           select sg;
                foreach (var data in list)
                {
     
                    Console.WriteLine(data.Key);
                    foreach (var item in data)
                    {
     
                        Console.WriteLine($"{item.Id} {item.Name} {item.Age}");
                    }
                }
//group by
                Console.WriteLine("********************");
                var list = from s in studentList
                           where s.Age < 30
                           group s by s.ClassId into sg
                           select new
                           {
     
                               key = sg.Key,
                               maxAge = sg.Max(t => t.Age)
                           };
 var list = studentList.GroupBy(s => s.ClassId).Select(sg => new
                {
     
                    key = sg.Key,
                    maxAge = sg.Max(t => t.Age)
                });
var list = from s in studentList
                           join c in classList on s.ClassId equals c.Id//不能用==只能equals
                           select new
                           {
     
                               Name = s.Name,
                               CalssName = c.ClassName
                           };
  var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new
                {
     
                    Name = s.Name,
                    CalssName = c.ClassName
                });
 var list = from s in studentList
                           join c in classList on s.ClassId equals c.Id
                           into scList
                           from sc in scList.DefaultIfEmpty()//
                           select new
                           {
     
                               Name = s.Name,
                               CalssName = sc == null ? "无班级" : sc.ClassName//c变sc,为空则用
                           };
 var list = studentList.Join(classList, s => s.ClassId, c => c.Id, (s, c) => new
                {
     
                    Name = s.Name,
                    CalssName = c.ClassName
                }).DefaultIfEmpty();//为空就没有了

Linq To SQL

  1. 在Queryable类,针对IQueryable数据, 操作数据库
  2. 程序访问数据库,都是需要Ado.Net+Sql
  3. 封装一下通用数据库操作,可变的是SQL,SQL通过表达式目录树(单独一章介绍表达式目录树)来传递,这个是可以解析的
   IQueryable<Student> list = studentList.AsQueryable();
                list.Where<Student>(s => s.Age > 30);//操作数据库

总结

这是一种伟大的封装思想,希望通过一种模式完成一切数据源的访问,让开发者彻底变成小白,(当年,潮流是傻瓜式,这种很厉害;现代化的开发有更高要求)

你可能感兴趣的:(C#基础语法学习笔记,.NET学习笔记,高级课程,c#)