服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - 带你一文了解C#中的LINQ

带你一文了解C#中的LINQ

2022-12-13 12:22RyzenAdorer C#

c#提供的ling查询极大的遍历了集合的查询过程,且使用简单方便,非常的有用,下面这篇文章主要给大家介绍了关于C#中LINQ的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

前言

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

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

LINQ的根基

IEnumerable和IEnumerator

为啥能够被foreach?

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

?
1
2
3
4
5
6
7
8
9
10
11
public interface IEnumerator
{
    object Current
    {
        get;
    }
 
    bool MoveNext();
 
    void Reset();
}
  • Current:集合当前的对象
  • MoveNext:是否能够移动到下一次
  • Reset

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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功能类似的简化版:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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就是为了简单的能够处理复杂集合的数据,那么扩展方法就能够实现较为简单的链式查询,例如:

?
1
2
3
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的查询表达式来编写,则写法是这样:

?
1
2
3
4
5
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的接口定义:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface IQueryable : IEnumerable
{
 
    Type ElementType
    {
        get;
    }
 
 
    Expression Expression
    {
        get;
    }
 
    IQueryProvider Provider
    {
        get;
    }
}

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

  • ElementType:集合的类型
  • Expression:表达式树,这是延迟执行的重点,下面我们会一窥究竟
  • IQueryProvider:IQueryable创建表达式树和执行的部分
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface IQueryProvider
{
 
    IQueryable CreateQuery(Expression expression);
 
 
    IQueryable<TElement> CreateQuery<TElement>(Expression expression);
 
 
    object? Execute(Expression expression);
 
 
    TResult Execute<TResult>(Expression expression);
}

我们先来看段代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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里面的方法

附:将内存中对象转换为 XML

LINQ 查询可以轻松地在内存中数据结构、SQL 数据库、ADO.NET 数据集和 XML 流或文档之间转换数据。 以下示例将内存中数据结构中的对象转换为 XML 元素。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class XMLTransform
{
    static void Main()
    {
        // Create the data source by using a collection initializer.
        // The Student class was defined previously in this topic.
        List<Student> students = new List<Student>()
        {
            new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores = new List<int>{97, 92, 81, 60}},
            new Student {First="Claire", Last="O'Donnell", ID=112, Scores = new List<int>{75, 84, 91, 39}},
            new Student {First="Sven", Last="Mortensen", ID=113, Scores = new List<int>{88, 94, 65, 91}},
        };
 
        // Create the query.
        var studentsToXML = new XElement("Root",
            from student in students
            let scores = string.Join(",", student.Scores)
            select new XElement("student",
                       new XElement("First", student.First),
                       new XElement("Last", student.Last),
                       new XElement("Scores", scores)
                    ) // end "student"
                ); // end "Root"
 
        // Execute the query.
        Console.WriteLine(studentsToXML);
 
        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}

此代码生成以下 XML 输出:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<Root
  <student
    <First>Svetlana</First
    <Last>Omelchenko</Last
    <Scores>97,92,81,60</Scores
  </student
  <student
    <First>Claire</First
    <Last>O'Donnell</Last
    <Scores>75,84,91,39</Scores
  </student
  <student
    <First>Sven</First
    <Last>Mortensen</Last
    <Scores>88,94,65,91</Scores
  </student
</Root>

参考

《C#7.0核心技术指南》

源码

BlogCodeSample/LinqSample at main · ZhengDaoWang/BlogCodeSample

总结

到此这篇关于C#中LINQ的文章就介绍到这了,更多相关C#的LINQ内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/ryzen/p/15674607.html

延伸 · 阅读

精彩推荐
  • C#C#语法新特性之元组实例详解

    C#语法新特性之元组实例详解

    元组(Tuple)在4.0 的时候就有了,但元组也有些缺点,具体那些缺点,本文给大家介绍的非常详细,本文重点给大家C#语法新特征之元组,感兴趣的朋友一起...

    jovenlee4762021-12-31
  • C#C#实现闪动托盘图标效果的方法

    C#实现闪动托盘图标效果的方法

    这篇文章主要介绍了C#实现闪动托盘图标效果的方法,涉及C# ImageList控件的使用技巧,需要的朋友可以参考下...

    冇一朵小尐尒尕尗尛尜5432021-11-24
  • C#C#实现QQ邮箱发送邮件

    C#实现QQ邮箱发送邮件

    今天小编就为大家分享一篇关于C#实现QQ邮箱发送邮件,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...

    chenqiangdage8232022-03-08
  • C#C#创建、部署、调用WebService图文实例详解

    C#创建、部署、调用WebService图文实例详解

    本文主要用详细的图文给大家介绍C#创建、部署、调用WebService的全部过程以及中间需要避免的问题。...

    laozhang5912022-02-12
  • C#详解C#打开和关闭可执行文件

    详解C#打开和关闭可执行文件

    这篇文章主要介绍了C#打开和关闭可执行文件,以QQ应用程序为例,需要的朋友可以参考下...

    Medeor5262021-11-05
  • C#详细分析c# 运算符重载

    详细分析c# 运算符重载

    这篇文章主要介绍了c# 运算符重载的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下...

    菜鸟教程11962022-09-28
  • C#WinForm天猫双11自动抢红包源码分享

    WinForm天猫双11自动抢红包源码分享

    这篇文章主要为大家分享了WinForm天猫双11自动抢红包源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    polk611132021-12-08
  • C#VSCode调试C#程序及附缺失.dll文件的解决办法

    VSCode调试C#程序及附缺失.dll文件的解决办法

    这篇文章主要介绍了VSCode调试C#程序及附缺失.dll文件的解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需...

    khq溪风8452022-10-10