zoukankan      html  css  js  c++  java
  • 了解LINQ

    本文主要的是泛谈LINQ是啥?以及常见的用法大纲如下:

    • LINQ的那些根基
    • LINQ的一些基本用法

    LINQ的根基

    IEnumerable和IEnumerator

    为啥能够被foreach?

    实际上,能够被foreach的对象,一定是实现了带有返回值的IEnumerator的GetEnumerator()方法的接口,而.NET内置的该接口则是IEnumerable,一般指的是IEnumerable泛型接口,让我们来看看IEnumerator接口有啥成员:

    
       public interface IEnumerator
       {
           object Current
           {
               get;
           }
    
           bool MoveNext();
    
           void Reset();
       }
    
    
    • Current:集合当前的对象
    • MoveNext:是否能够移动到下一次
    • Reset

    因此,实际上我们进行foreach的时候,等价于:

    var animals = new List<string>() { "Cat", "Dog", "Pig" };
    
    foreach (var animla in animals)
    {
        Console.WriteLine(animla);
    }
    Console.WriteLine("-----------");
    
    var enumerator = animals.GetEnumerator();
    while (enumerator.MoveNext())
    {
        Console.WriteLine(enumerator.Current);
    }
    
    
    

    输出结果:

    Cat
    Dog
    Pig
    -----------
    Cat
    Dog
    Pig
    
    

    而能被LINQ的对象就是一个实现了IEnumerable的可被枚举的集合

    LINQ的基本用法

    扩展方法在LINQ的应用:LINQ的流式语法

    LINQ的方法一般都是通过扩展方法了扩展的,就如最常用的几个,Where,Any,例如,我实现了一个跟Where功能类似的简化版:

    
     public static class MyListExtension
    {
        public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> enumable, Func<T, bool> func)
        {
            foreach (var item in enumable)
            {
                if (func(item))
                {
                    yield return item;
                }
            }
        }
    }
    
    

    其实为啥会提到用扩展方法呢?就是因为LINQ就是为了简单的能够处理复杂集合的数据,那么扩展方法就能够实现较为简单的链式查询,例如:

    
    var result= animals.MyWhere(t => t is "Cat" or "Dog").Select(t=>t.ToUpper()).ToList();
    
    result.ForEach(t =>Console.WriteLine(t));
    
    
    

    输出结果:

    CAT
    DOG
    
    

    LINQ的查询表达式:LINQ的查询语法

    假如上述的例子有LINQ的查询表达式来编写,则写法是这样:

    
    var result = (from t in animals
                  where t is "Cat" or "Dog"
                  select t.ToUpper()).ToList();
    
    result.ForEach(t => Console.WriteLine(t));
    
    
    

    输出结果也是一样的:

    CAT
    DOG
    
    

    LINQ的延迟执行:IQueryable

    首先我们来看看IQueryable的接口定义:

    
        public interface IQueryable : IEnumerable
        {
    
            Type ElementType
            {
                get;
            }
    
     
            Expression Expression
            {
                get;
            }
    
            IQueryProvider Provider
            {
                get;
            }
        }
    
    

    我们可以看到实际上IQueryable是继承了IEnumerable,因此同样具备其特性,然后主要看其三个属性:

    • ElementType:集合的类型
    • Expression:表达式树,这是延迟执行的重点,下面我们会一窥究竟
    • IQueryProvider:IQueryable创建表达式树和执行的部分
    
        public interface IQueryProvider
        {
      
            IQueryable CreateQuery(Expression expression);
    
      
            IQueryable<TElement> CreateQuery<TElement>(Expression expression);
    
    
            object? Execute(Expression expression);
    
    
            TResult Execute<TResult>(Expression expression);
        }
    
    

    我们先来看段代码:

    
    var result1 = (from t in animals
                    where (t.Equals( "Cat") || t.Equals("Dog"))
                    select t.ToUpper()).AsQueryable();
    Console.WriteLine($"Expression:{ result1.Expression.ToString()}");
    Console.WriteLine($"ExpressionType:{result1.Expression.GetType()}");
    foreach (var item in result1)
    {
        Console.WriteLine(item);
    }
    
    Console.WriteLine("---------------");
    var result2 = from t in result1
                  where  t.Contains("CAT")
                  select t;
    Console.WriteLine($"Expression:{ result2.Expression.ToString()}");
    Console.WriteLine($"ExpressionType:{result2.Expression.GetType()}");
    foreach (var item in result2)
    {
        Console.WriteLine(item);
    }
    
    

    输出如下:

    Expression:System.Linq.Enumerable+WhereSelectListIterator`2[System.String,System.String]
    ExpressionType:System.Linq.Expressions.ConstantExpression
    CAT
    DOG
    ---------------
    Expression:System.Linq.Enumerable+WhereSelectListIterator`2[System.String,System.String].Where(t => t.Contains("CAT"))
    ExpressionType:System.Linq.Expressions.MethodCallExpression2
    CAT
    
    

    我们从输出可以证明,实际上在返回result1和result2,就是通过IQueryProvider不断地在拼接表达式树,而最后通过foreach或者ToList等操作的时候,则才是真正调用Execute方法执行当前的IQueryable里的那个表达式树属性Expression,而像LINQ To Sql或者是EFCore等需要IQueryable这种解释型的就是去实现了IQueryProvider里面的方法

    参考

    • 《C#7.0核心技术指南》

    源码

  • 相关阅读:
    Linux命令集
    Java实现 LeetCode 648 单词替换(字典树)
    pci常用命令
    pci 设备 vendor device subsystem 驱动
    手动绑定驱动 + drivers_probe + rescan
    找不到网卡 pci probe function not called
    primary + secondary + malloc + rte_memzone_reserve
    gdb 打印结构体
    rte_fbarray_init
    DPDK 内存管理---malloc_heap和malloc_elem
  • 原文地址:https://www.cnblogs.com/ryzen/p/15674607.html
Copyright © 2011-2022 走看看