欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

.NET学习(8)语言集成查询 (LINQ)

程序员文章站 2022-07-04 09:06:29
...

MS文档:LINQ

语言集成查询 (LINQ) 是一系列直接将查询功能集成到 C# 语言的技术统称。

  • 用最少的代码对数据源执行筛选、排序和分组操作
  • 对不同类型的数据源提供统一的数据访问接口:SQL 数据库、ADO .NET 数据集、XML 文档和流以及 .NET 集合中的数据

LINQ的种类

1. LINQ to Objects 的使用

可以使用 LINQ 来查询任何可枚举的集合,例如 List<T>ArrayDictionary<TKey,TValue>。 该集合可以是用户定义的集合,也可以是由 .NET Framework API 返回的集合。

using System;
using System.Linq;

namespace program
{
    public class Program
    {
        public static void Main(string[] args)
        {
            string[] greetings = {"Hello", "Hi", "How are you"};
            var items = from s in greetings
                        where s.Length >= 5
                        select s;
            foreach(var item in items)
            {
                Console.WriteLine(item);
            }
            return;
        }
    }
}
// output:
// Hello
// How are you

LINQ 查询与传统 foreach 循环相比具有三大优势

  • 它们更简明、更易读,尤其在筛选多个条件时
  • 它们使用最少的应用程序代码提供强大的筛选、排序和分组功能
  • 无需修改或只需做很小的修改即可将它们移植到其他数据源

LINQ to Objects 的实现基于:

  • IEnumerable<T>范型接口
  • 序列<sequences>,实现 IEnumerable<T>的集合对象
  • 标准查询操作符,就是扩展方法[select where]

IEnumerable
IEnumerable 是可枚举的所有非泛型集合的基接口。它包含一个方法,GetEnumerator ,它将返回 IEnumerator。

IEnumerator
IEnumerator 是所有非泛型枚举器的基接口。支持对非泛型集合的简单迭代。
IEnumerator 提供了通过公开循环访问集合的功能Current属性和MoveNextReset方法。

最佳实践
在自己的集合类上实现 IEnumerable 和 IEnumerator 两个接口,用以支持foreach语法。其中,实现 IEnumerable 不是必要的。

2. 创建可枚举的类

MyEnumerable

    public class MyEnumerable: IEnumerable
    {
        public int StartCountDown;
        public IEnumerator GetEnumerator()
        {
            return new MyEnumerator(this);
        }
    }

MyEnumerator

    public class MyEnumerator: IEnumerator
    {
        private int cur;
        private MyEnumerable owner;
        public MyEnumerator(MyEnumerable countdown)
        {
            owner = countdown;
            Reset();
        }
        public void Reset()
        {
            cur = owner.StartCountDown;
        }
        public bool MoveNext()
        {
            if (cur > 0)
            {
                cur--;
                return true;
            }
            return false;
        }
        public object Current {  get { return cur; } }
    }

Program::Main()

    public class Program
    {
        public static void Main(string[] args)
        {
            // 一个可枚举类的实例对象
            MyEnumerable obj = new MyEnumerable { StartCountDown = 20 };

            // 方式一:手动迭代
            IEnumerator enu = obj.GetEnumerator();
            while (enu.MoveNext())
            {
                Console.WriteLine((int)enu.Current);
            }
            // 方式二:使用foreach语法进行迭代
            foreach(var i in obj)
            {
                Console.WriteLine(i);
            }
        }
    }

3. yield的使用

MyYield

    public class MyYield: IEnumerable
    {
        public int StartCountDown;
        public IEnumerator GetEnumerator()
        {
            for(int i=StartCountDown-1; i>=0; i--)
            {
                yield return i;
            }
        }
    }

Program::Main()

    public class Program
    {
        public static void Main(string[] args)
        {
            // 一个可枚举类的实例对象
            MyYield obj = new MyYield { StartCountDown = 20 };

            // 方式一:手动迭代
            IEnumerator enu = obj.GetEnumerator();
            while (enu.MoveNext())
            {
                Console.WriteLine((int)enu.Current);
            }
            // 方式二:使用foreach语法进行迭代
            foreach(var i in obj)
            {
                Console.WriteLine(i);
            }
        }
    }

4. LINQ 标准操作符的使用

示例使用的字符串数组:

string[] array = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" };

1. Where(1)

            Console.WriteLine("--- --- --- 1. Where(1) --- --- ---");
            var items1 = array.Where(p => p.StartsWith("t", StringComparison.Ordinal));
            foreach(string item in items1)
            {
                Console.WriteLine(item);
            }
/* output:
two
three
ten
*/

2. Where(2)

            Console.WriteLine("--- --- --- 2. Where(2) --- --- ---");
            var items2 = array.Where((p, i) =>
            {
                if (i > 2)
                    return p.StartsWith("t", StringComparison.Ordinal);
                else
                    return false;
            });
            foreach (string item in items2)
            {
                Console.WriteLine(item);
            }
/* output:
ten
*/

3. 延迟执行

延迟执行是指,在定义items3的时候,并不是真正获取到一个集合,而是在foreach的时候才去获取相应地值。所以,在遍历items3的时候,可以看到对array[2]的修改也体现了出来,即使这个修改发生在定义items3之后。

            Console.WriteLine("--- --- --- 3. 延迟执行 --- --- ---");
            var items3 = array.Where(p => p.StartsWith("t", StringComparison.Ordinal));
            array[2] = "t5000";
            foreach (string item in items3)
            {
                Console.WriteLine(item);
            }
/* output:
two
t5000
ten
*/

4. 非延迟执行

由于调用了ToList()方法,在定义items4的时候就已经遍历了array并获取相应的值。所以,后续更改array的操作不会反映到items4中。

            Console.WriteLine("--- --- --- 4. 非延迟执行 --- --- ---");
            var items4 = array.Where(p => p.StartsWith("t", StringComparison.Ordinal)).ToList();
            array[2] = "t6000";
            foreach (string item in items4)
            {
                Console.WriteLine(item);
            }
            array[2] = "three"; // 复原
/* output:
two
t5000
ten
*/

5. Select(1)

            Console.WriteLine("--- --- --- 5. Select(1) --- --- ---");
            var items6 = array.Select(p => p.Length);
            foreach(int item in items6) 
            {
                Console.WriteLine(item);
            }
/* output:
3
3
5
4
4
3
5
5
4
3
*/

6. Select(2)

            Console.WriteLine("--- --- --- 6. Select(2) --- --- ---");
            var items7 = array.Select((p, i) => new { Index = i, Name = p });
            foreach(var item in items7)
            {
                Console.WriteLine(item);
            }
/* output:
{ Index = 0, Name = one }
{ Index = 1, Name = two }
{ Index = 2, Name = three }
{ Index = 3, Name = four }
{ Index = 4, Name = five }
{ Index = 5, Name = six }
{ Index = 6, Name = seven }
{ Index = 7, Name = eight }
{ Index = 8, Name = nine }
{ Index = 9, Name = ten }
*/

7. SelectMany

            Console.WriteLine("--- --- --- 7. SelectMany --- --- ---");
            var items8 = array.SelectMany(p => p.ToCharArray());
            foreach (var item in items8)
            {
                Console.WriteLine(item);
            }
/* output:
o
n
e
t
w
o
……
*/

8. Take

            Console.WriteLine("--- --- --- 8. Take --- --- ---");
            var items9 = array.Take(3);
            foreach (var item in items9)
            {
                Console.WriteLine(item);
            }
/* output:
one
two
three
*/

9. TakeWhile

            Console.WriteLine("--- --- --- 9. TakeWhile --- --- ---");
            var items10 = array.TakeWhile(p => p.Length < 4);
            foreach (var item in items10)
            {
                Console.WriteLine(item);
            }
/* output:
one
two
*/

10. Skip

            Console.WriteLine("--- --- --- 10. Skip --- --- ---");
            var items11 = array.Skip(3);
            foreach (var item in items11)
            {
                Console.WriteLine(item);
            }
/* output:
four
five
six
seven
eight
nine
ten
*/

11. SkipWhile

            Console.WriteLine("--- --- --- 11. SkipWhile --- --- ---");
            var items12 = array.SkipWhile(p => p.Length < 4);
            foreach (var item in items12)
            {
                Console.WriteLine(item);
            }
/* output:
three
four
five
six
seven
eight
nine
ten
*/

12. OrderBy(1)

            Console.WriteLine("--- --- --- 12. OrderBy(1) --- --- ---");
            var items13 = array.OrderBy(p => p.Length);
            foreach (var item in items13)
            {
                Console.WriteLine(item);
            }
/* output:
one
two
six
ten
four
five
nine
three
seven
eight
*/

13. OrderBy(2)

            Console.WriteLine("--- --- --- 13. OrderBy(2) --- --- ---");
            var items14 = array.OrderBy(p => p.Length).Take(5);
            foreach (var item in items14)
            {
                Console.WriteLine(item);
            }
/* output:
one
two
six
ten
four
*/

5. 连接操作(Join)

两个类,Student和Score

        public class Student
        {
            public int Id;
            public string Name;
            public int Age;
        }

        public class Score
        {
            public int StudentId;
            public float English;
            public float Maths;
        }

Program::Main()

    public class Program
    {
        public static void Main(string[] args)
        {
            // 数据初始化
            Student[] students = new Student[]
            {
               new Student{Id=1, Name="1", Age=20},
               new Student{Id=2, Name="2", Age=19},
               new Student{Id=3, Name="3", Age=21},
               new Student{Id=4, Name="4", Age=20}
           };
            Score[] scores = new Score[]
            {
                new Score{StudentId=1, English=90, Maths=80},
                new Score{StudentId=1, English=91, Maths=85},
                new Score{StudentId=1, English=92, Maths=86},
                new Score{StudentId=1, English=93, Maths=82}
            };

            // 查询 1
            Console.WriteLine("--- list 1 ---");
            var list1 = students.Join(scores, o => o.Id, i => i.StudentId, 
                (o, i) => new { o.Name, i.English, i.Maths });
            foreach(var ele in list1)
            {
                Console.WriteLine(ele);
            }
            // 查询 2
            Console.WriteLine("--- list 2 ---");
            var list2 = from o in students
                        from i in scores
                        where o.Id == i.StudentId
                        orderby i.Maths
                        select new { o.Name, i.English, i.Maths };
            foreach (var ele in list2)
            {
                Console.WriteLine(ele);
            }
        }

    }
/* output
--- list 1 ---
{ Name = 1, English = 90, Maths = 80 }
{ Name = 1, English = 91, Maths = 85 }
{ Name = 1, English = 92, Maths = 86 }
{ Name = 1, English = 93, Maths = 82 }
--- list 2 ---
{ Name = 1, English = 90, Maths = 80 }
{ Name = 1, English = 93, Maths = 82 }
{ Name = 1, English = 91, Maths = 85 }
{ Name = 1, English = 92, Maths = 86 }
*/

转载于:https://www.jianshu.com/p/2c9a269099c7