第7章:Linq


本章目标

  1. 掌握Linq的运用

本章内容

Linq概述

什么是Linq

Lanaguage Interated Query(语言集成查询),Linq 是集成C# 和VB这些语言中用于提供数据查询能力的一个新特性。Linq用于以对象形式管理关系数据,并提供了丰富的查询功能。

LINQ是一组语言特性和API,使得你可以使用统一的方式编写各种查询。用于保存和检索来自不同数据源的数据,从而消除了编程语言和数据库之间的不匹配,以及为不同类型的数据源提供单个查询接口。

LINQ总是使用对象,因此你可以使用相同的查询语法来查询和转换XML、对象集合、SQL数据库、ADO.NET数据集以及任何其他可用的LINQ提供程序格式的数据。

LInq支持的数据源

  • LINQ to Objects 主要负责对象的查询。
  • LINQ to XML 主要负责XML的查询。
  • LINQ to ADO.NET 主要负责数据库的查询。
    • LINQ to SQL
    • LINQ to DataSet
    • LINQ to Entities

Linq的优势

1、熟悉的语言:开发人员不必为每种类型的数据源或数据格式学习新的语言。

2、更少的编码:相比较传统的方式,LINQ减少了要编写的代码量。

3、可读性强:LINQ增加了代码的可读性,因此其他开发人员可以很轻松地理解和维护。

4、标准化的查询方式:可以使用相同的LINQ语法查询多个数据源。

5、类型检查:程序会在编译的时候提供类型检查。

6、智能感知提示:LINQ为通用集合提供智能感知提示。

7、整形数据:LINQ可以检索不同形状的数据。

匿名类型

  1. 匿名类型是可以创建无名类型的一种类型,经常用于LINQ查询的结果中。

  2. 匿名类型只能和局部变量配合使用,不能用于类成员。

  3. 匿名类型没有名字,必须使用var关键字作为变量类型。

  4. 编译器为匿名对象创建的属性是只读的,所以不能设置匿名类型对象的属性。

  5. 格式:

    1
    2
    3
    4
    5
    6
    static void Fun1()
    {
    var man = new { Name="孙悟空", Age = 25, Sex='男' };

    Console.WriteLine("姓名:{0}, 年龄:{1}, 性别:{2}", man.Name, man.Age, man.Sex);
    }

方法语法和查询语法

初识查询语法和方法语法

  1. 我们使用LINQ查询时可以使用两种形式的语法:方法语法和查询语法。

  2. 方法语法:使用标准的方法调用,这些方法是一组叫做标准查询运算符的方法。方法语法命令式的,指明了查询方法调用的顺序。

  3. 查询语法:类似于SQL语句,使用查询表达式形式书写。查询语法是声明式的,查询描述的是你想返回的东西,但并没有指明如何执行这个查询。

    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
    static void Fun2()
    {
    int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    //查询语法
    IEnumerable<int> result1 = from n in nums
    where n > 4 && n < 8
    select n;

    //方法语法
    IEnumerable<int> result2 = nums.Where(x => (x > 4 && x < 8));//返回枚举

    //两种形式的组合
    int count = (from n in nums where n > 4 && n < 8 select n).Count();//返回单个值

    //查看结果
    foreach (int i in result1)
    Console.Write(i);
    Console.WriteLine();

    foreach (int i in result2)
    Console.Write(i);
    Console.WriteLine();

    Console.Write(count);

    }

查询变量

  • LINQ查询可以返回两种类型的结果,如下:

    • 枚举:包含了一组数据

    • 标量:一个单一的值

  • 理解查询变量:

    • 如果查询表达式返回枚举,查询一直到处理枚举时才会执行。(延迟执行)
    • 如果枚举被处理多次,查询就会执行多次。
    • 如果在进行遍历之后,查询执行之前数据有改动,则查询会使用新的数据。
    • 如果查询表达式返回标量,查询立即执行,并把结果保存在查询变量中。

查询表达式的结构

查询表达式由查询体后的from子句组成。

  1. 子句必须按照一定的顺序。
  2. from子句和select…group这两部分是必需的。
  3. 其他子句是可选的。
  4. 可以有任意多的from…let…where子句。

from子句

  • from子句和foreach子句格式十分相似,但实际有很大区别:

    • foreach语句命令式指定了按顺序一个个访问集合中的项。from子句只是声明式地规定集合中的每个项都要访问,并没有指定顺序。
    • foreach在遇到代码时就执行其主体。from子句什么也不执行,只有在遇到访问查询变量的语句时才会执行。
  • 格式:

  • 代码示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    static void Fun3()
    {
    int[] ints = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    var nums = from n in ints
    where n > 7 //使用迭代变量n
    select n; //使用迭代变量n

    foreach (var n in nums)
    Console.WriteLine(n);
    }

join子句

  • 注意事项:

    • 使用联结来结合两个或更多集合中的数据。
    • 联结对象接受两个集合,然后创建一个临时的对象集合,每一个对象包含原始集合对象中的所有字段。
    • 字段只能使用equals比较,不能使用==
  • 格式:

  • 代码示例:

    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    /// <summary>
    /// 学生
    /// </summary>
    class Student
    {
    /// <summary>
    /// 学号
    /// </summary>
    public string StudentNo { get; set; }

    /// <summary>
    /// 姓名
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// 年龄
    /// </summary>
    public int Age { get; set; }

    /// <summary>
    /// 性别
    /// </summary>
    public char Sex { get; set; }
    }

    /// <summary>
    /// 成绩
    /// </summary>
    class Result
    {
    /// <summary>
    /// 学号
    /// </summary>
    public string StudentNo { get; set; }

    /// <summary>
    /// 科目
    /// </summary>
    public string Subject { get; set; }

    /// <summary>
    /// 分数
    /// </summary>
    public int Score { get; set; }
    }
    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
    static void Fun4()
    {
    //学生
    Student[] students = new Student[] {
    new Student { StudentNo="GCKJ001", Name="曾令耀", Age=18,Sex='男' },
    new Student { StudentNo="GCKJ002", Name="李尚驰", Age=18,Sex='男' },
    new Student { StudentNo="GCKJ003", Name="黄朗云", Age=18,Sex='女' }
    };

    //成绩
    Result[] courseStudents = new Result[] {
    new Result { StudentNo="GCKJ001",Subject="java"},
    new Result { StudentNo="GCKJ002",Subject="c#"},
    new Result { StudentNo="GCKJ002",Subject="python"},
    new Result { StudentNo="GCKJ003",Subject="python"},
    new Result { StudentNo="GCKJ001",Subject="c#"},
    new Result { StudentNo="GCKJ003",Subject="java"},
    };

    //查询所有选择了c#课的学生
    var query = from s in students
    join c in courseStudents on s.StudentNo equals c.StudentNo
    where c.Subject == "c#"
    select s.Name;

    foreach (var e in query)
    Console.WriteLine(e);
    }

from…let…where片段

可选的from…let…where部分是查询主体的第一部分,可以由任意数量的from子句、let子句、where子句来组合。

  • 多个from子句

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    static void Fun5()
    {
    var groupA = new[] { 3, 4, 5, 6 };
    var groupB = new[] { 6, 7, 8, 9 };

    var someInts = from a in groupA //必需的第一个from子句
    from b in groupB //查询主体的第一个from子句
    where a > 4 && b <= 8
    select new { a, b, sum = a + b };//匿名类型对象

    foreach (var e in someInts)
    Console.WriteLine(e);
    }
  • let子句

    let子句接受一个表达式的运算并且把它赋值给一个需要在其他运算中使用的标识符。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    static void Fun6()
    {
    var groupA = new[] { 3, 4, 5, 6 };
    var groupB = new[] { 6, 7, 8, 9 };

    var someInts = from a in groupA
    from b in groupB
    let sum = a + b
    where sum == 12
    select new { a, b, sum };

    foreach (var e in someInts)
    Console.WriteLine(e);
    }
  • 多个where子句

    where子句根据之后的运算来去除不符合条件的项。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    static void Fun7()
    {
    var groupA = new[] { 3, 4, 5, 6 };
    var groupB = new[] { 6, 7, 8, 9 };

    var someInts = from a in groupA
    from b in groupB
    let sum = a + b
    where sum >= 11 //选择sum>=11的
    where a == 4 //选择a==4的
    select new { a, b, sum };//存放满足两种条件的匿名类

    foreach (var e in someInts)
    Console.WriteLine(e);
    }

orderby子句

orderby接受一个表达式,并根据表达式按顺序返回结果项。orderby子句默认升序,可以使用ascending和descending来指定升序还是降序 .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static void Fun8()
{
//匿名类型的对象数组
var students = new[]
{
new { Name = "光头强", Age = 25, Course = "体育" },
new { Name = "熊大", Age = 17, Course = "美术" },
new { Name = "熊二", Age = 16, Course = "历史" },
new { Name = "喜羊羊", Age = 13, Course = "历史" },
new { Name = "懒羊羊", Age = 14, Course = "历史" },
new { Name = "沸羊羊", Age = 15, Course = "历史" },
};

var stu = from s in students
orderby s.Age
select s;

foreach (var student in stu)
Console.WriteLine("{0},{1},{2}", student.Name, student.Age, student.Course);
}

select子句

select子句指定所选对象的哪部分应该被选择。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static void Fun9()
{

//匿名类型的对象数组
var students = new[]
{
new { Name = "光头强", Age = 25, Course = "体育" },
new { Name = "熊大", Age = 17, Course = "美术" },
new { Name = "熊二", Age = 16, Course = "历史" },
new { Name = "喜羊羊", Age = 13, Course = "历史" },
new { Name = "懒羊羊", Age = 14, Course = "历史" },
new { Name = "沸羊羊", Age = 15, Course = "历史" },
};

var stu = from s in students
select s.Name; //只选择数据项中的学生名字

foreach (var student in stu)
Console.WriteLine("{0}", student);
}

查询中的匿名类型

可以在select子句后创建匿名类型存放指定查询的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static void Fun10()
{
//匿名类型的对象数组
var students = new[]
{
new { Name = "光头强", Age = 25, Course = "体育" },
new { Name = "熊大", Age = 17, Course = "美术" },
new { Name = "熊二", Age = 16, Course = "历史" },
new { Name = "喜羊羊", Age = 13, Course = "历史" },
new { Name = "懒羊羊", Age = 14, Course = "历史" },
new { Name = "沸羊羊", Age = 15, Course = "历史" },
};

var stu = from s in students
select new { s.Name, s.Age };//创建匿名类型存放需要的数据

foreach (var student in stu)
Console.WriteLine("{0}\t{1}", student.Name, student.Age);

}

group子句

group子句把select的对象根据一些标准进行分组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static void Fun11()
{
//匿名类型的对象数组
var students = new[]
{
new { Name = "光头强", Age = 25, Course = "体育" },
new { Name = "熊大", Age = 17, Course = "美术" },
new { Name = "熊二", Age = 16, Course = "历史" },
new { Name = "喜羊羊", Age = 13, Course = "历史" },
new { Name = "懒羊羊", Age = 14, Course = "历史" },
new { Name = "沸羊羊", Age = 15, Course = "历史" },
};

var groups = from s in students
group s by s.Course;//根据学科进行分组

foreach (var g in groups)
{
Console.WriteLine(g.Key);//分组键

foreach (var s in g)
Console.WriteLine(" {0},{1}", s.Name, s.Age);
}
}

查询延续:into子句

查询延续子句可以接受查询的一部分结果并赋予一个名字,从而可以在查询的另一部分中使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static void Fun12()
{
int[] groupA = { 1, 2, 3, 4, 5, 6, 7, 8, };
int[] groupB = { 5, 6, 7 };

//将groupA、groupB的联合查询的结果延续一个新名字groupAandB,然后继续新的查询
IEnumerable<int> ints = from a in groupA
join b in groupB on a equals b
into groupAandB
from c in groupAandB
select c;

foreach (int i in ints)
Console.WriteLine(i);

}

Linq应用综合案例

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
static void Fun13()
{
//数据源
List<Student> stuList = new List<Student>() {
new Student{ StudentNo="GCKJ001", Name="唐僧", Age=18,Sex='男'},
new Student{ StudentNo="GCKJ002", Name="孙悟空", Age=17,Sex='男'},
new Student{ StudentNo="GCKJ003", Name="猪八戒", Age=16,Sex='男'},
new Student{ StudentNo="GCKJ004", Name="沙僧", Age=15,Sex='男'},
new Student{ StudentNo="GCKJ005", Name="白龙马", Age=12,Sex='男'},
new Student{ StudentNo="GCKJ006", Name="蜘蛛精", Age=21,Sex='女'},
new Student{ StudentNo="GCKJ007", Name="白骨精", Age=22,Sex='女'},
new Student{ StudentNo="GCKJ008", Name="白鹤仙子", Age=23,Sex='女'},
new Student{ StudentNo="GCKJ009", Name="玉面狐狸精", Age=18,Sex='女'},
new Student{ StudentNo="GCKJ011", Name="嫦娥", Age=30,Sex='女'},
new Student{ StudentNo="GCKJ011", Name="女儿国国王", Age=25,Sex='女'},
new Student{ StudentNo="GCKJ012", Name="万圣公主", Age=17,Sex='女'},
new Student{ StudentNo="GCKJ013", Name="太白金星", Age=35,Sex='男'},
new Student{ StudentNo="GCKJ014", Name="王母", Age=35,Sex='女'},
new Student{ StudentNo="GCKJ015", Name="玉帝", Age=100,Sex='男'},
new Student{ StudentNo="GCKJ016", Name="如来", Age=100,Sex='男'}
};

#region 简单的函数计算(count,min,max,sum)

var count = (from stu in stuList
select stu).Count();
var max = (from stu in stuList
select stu).Max<Student>(p => p.Age);
var min = (from stu in stuList
select stu).Min<Student>(p => p.Age);
var sum = (from stu in stuList
select stu).Sum<Student>(p => p.Age);

Console.WriteLine("总数:{0}", count);
Console.WriteLine("最大年龄:{0}", max);
Console.WriteLine("最小年龄:{0}", min);
Console.WriteLine("年龄总和:{0}", sum);

#endregion

#region First()/Last()

var q1 = (from stu in stuList
where stu.Age >= 18
orderby stu.Age descending
select stu).First<Student>();

var q2 = (from stu in stuList
where stu.Age >= 18
orderby stu.Age descending
select stu).Last<Student>();

Console.WriteLine(q1);
Console.WriteLine(q2);

#endregion

#region 跳过前面多少条数据取余下的数据

var query = (from stu in stuList
select stu).Skip<Student>(3);

foreach (var item in query)
{
Console.WriteLine(item);
}
#endregion

#region 分页数据查询

var query2 = (from stu in stuList
select stu).Skip(10).Take(5);

foreach (var item in query2)
{
Console.WriteLine(item);
}
#endregion

#region 分组group by

var q3 = from stu in stuList
where stu.Age >= 18
group stu by stu.Sex into ss
select ss;

foreach (var item in q3)
{
Console.WriteLine(string.Format("组:{0},人数:{1}", item.Key, item.Count()));
}

Console.WriteLine("----------------------------------------");

var q4 = from stu in stuList
where stu.Age >= 18
group stu by stu.Sex into ss
select new
{
ss.Key,
Count = ss.Count(),
MaxAge = ss.Max(p => p.Age)
};
foreach (var item in q4)
{
Console.WriteLine(string.Format("组:{0},人数:{1},最大年龄:{2}", item.Key, item.Count, item.MaxAge));
}

#endregion

#region sql中的in

var q5 = from stu in stuList
where (new int[] { 18, 100 }).Contains(stu.Age)
select stu;

foreach (var item in q5)
{
Console.WriteLine(item);
}
#endregion
}

Linq to xml

前序

操作之前,需要引入 程序集和命名空间 System.Xml.Linq; 

核心对象:

对象 描述
XDocument xml文档
XElement xml元素/结点
XDeclaration xml声明
XComment xml注释
XAttribute xml属性

生成XML

1.创建简单的xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/// <summary>
/// 创建XML
/// </summary>
static void CreateXml()
{
XDocument xdoc = new XDocument(
new XDeclaration("1.0","utf-8","yes"),
new XElement("NameList",
new XElement("Name","张三"),
new XElement("Name","李四")
)
);

xdoc.Save(path);

Console.WriteLine("ok");
}

2.创建带注释的xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/// <summary>
/// 创建带有注释的xml
/// </summary>
static void CreateComment()
{
XDocument xdoc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment("姓名列表"),
new XElement("NameList",
new XElement("Name", "张三"),
new XElement("Name", "李四")
)
);

xdoc.Save(path);
Console.WriteLine("ok");
}

3.根据对象创建xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/// <summary>
/// 根据对象创建XML
/// </summary>
static void CreateXmlByObjects()
{
int[] nums = { 35,27,19,54,100};

XElement xdoc = new XElement("NumList",
from item in nums
select new XElement("item", item.ToString())
);

xdoc.Save(path);

Console.WriteLine("ok");
}

4.创建带属性的xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/// <summary>
/// 创建带有属性的xml
/// </summary>
static void CreateAttribute()
{
//属性
XAttribute xr = new XAttribute("属性1","值1");

//元素
XElement xe = new XElement("root",
new XElement("item",
new XAttribute("属性2", "值2"),
xr
)
);

xe.Save(path);

Console.WriteLine("ok");
}

修改XML

新建一个test1.xml文件,并在其中写入如下内容:

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Item v1="1" v2="2">Item1</Item>
<Item v1="1" v2="2" >Item2</Item>
</Root>

1.通过文件读取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
33
34
35
36
/// <summary>
/// 读取XML
/// </summary>
static void QueryXml()
{
#region 方式1
////文档
//XDocument xd = XDocument.Load(path);

////元素
//XElement xe = xd.Element("Root"); //注意区分大小写

//Console.WriteLine(xe.Value.ToString());
#endregion

#region 方式2
////文档
//XDocument xd =XDocument.Load(path);

////元素
//XElement element = xd.Root.FirstNode as XElement;

//Console.WriteLine(element.Value.ToString());
#endregion

#region 方式3

XElement xe = XElement.Load(path);

XElement xe2 = xe.Element("item");

Console.WriteLine(xe2.Value.ToString());

#endregion

}

2.在指定节点前后添加新节点

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
/// <summary>
/// 插入元素到指定节点前后
/// </summary>
static void AddElement()
{
XElement xe= XElement.Load(path);

//目标元素
var Item = (from item in xe.Elements()
where item.Value.Equals("Item2")
select item).FirstOrDefault();

//新元素
XElement xe1 = new XElement("NItem", "新元素1");
XElement xe2 = new XElement("NItem", "新元素2");

//在目标元素前后插入新元素
Item.AddAfterSelf(xe1);
Item.AddBeforeSelf(xe2);

//保存
xe.Save(path);

Console.WriteLine( "ok");
}

3.添加属性到节点中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/// <summary>
/// 添加属性到节点中
/// </summary>
static void AddAttribute()
{
//根元素
XElement xe=XElement.Load(path);

//获取第一个子结点
var item = xe.Element("Item");

//设置属性
item.SetAttributeValue("V3", 3);

//保存
xe.Save(path);

Console.WriteLine( "ok");
}

4.添加注释到指定节点前后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/// <summary>
/// 添加注释到指定节点前后
/// </summary>
static void AddCommont()
{
//根节点
XElement xe = XElement.Load(path);

//目标结点
XElement item = xe.Elements("Item").FirstOrDefault();

//注释
XComment xc1 = new XComment("前面的注释");
XComment xc2 = new XComment("后面的注释");

//将注释插入到目标结点前后
item.AddBeforeSelf(xc1);
item.AddAfterSelf(xc2);

//保存
xe.Save(path);

Console.WriteLine("ok");
}

5.替换指定节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/// <summary>
/// 替换指定节点
/// </summary>
static void ReplactElement()
{
//根元素
XElement xe = XElement.Load(path);

//目标元素
XElement item=xe.Elements("Item").FirstOrDefault();

//替换为新元素
item.ReplaceWith(new XElement("Item","Item3"));

//保存
xe.Save(path);

Console.WriteLine("ok");
}

6.删除指定属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/// <summary>
/// 删除指定属性
/// </summary>
static void RemoveAttribute()
{
//根元素
XElement xe = XElement.Load(path);

//目标元素
XElement item = xe.Elements("Item").FirstOrDefault();

//移除指定属性
item.Attribute("v1").Remove();

//保存
xe.Save(path);

Console.WriteLine("ok");
}

7.删除指定节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/// <summary>
/// 删除指定结点
/// </summary>
static void RemoveElement()
{
//根元素
XElement xe = XElement.Load(path);

//目标元素
XElement item = xe.Elements("Item").FirstOrDefault();

//移除指定元素
item.Remove();

//保存
xe.Save(path);

Console.WriteLine("ok");
}

查询XML

下新建一个test2.xml并写入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8" ?>
<Root>
<Item>
<SubItem1>
1
</SubItem1>
<SubItem>
<Child>
sss
</Child>
</SubItem>
<SubItem2>
2
</SubItem2>
</Item>
</Root>

1.显示指定节点的所有父节点

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
/// <summary>
/// 显示指定结点的所有父结点
/// </summary>
static void ShowAllParent()
{
//根元素
XElement xe = XElement.Load(path);

//目标元素
XElement item = xe.Descendants("Child").FirstOrDefault();

//遍历当前节点的上级元素集合
foreach (var i in item.Ancestors())
{
Console.WriteLine(i.Name);
}

Console.WriteLine("----------------------------");

//遍历当前节点的上级元素集合(包含当前元素)
foreach (var i in item.AncestorsAndSelf())
{
Console.WriteLine(i.Name);
}
}

2.显示指定节点的所有子节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/// <summary>
/// 显示所有子结点
/// </summary>
static void ShowAllChild()
{
//根元素
XElement xe = XElement.Load(path);

//遍历子元素
foreach (var i in xe.Descendants())
{
Console.WriteLine(i.Name);
}

Console.WriteLine("------------------------");

foreach (var i in xe.DescendantsAndSelf())
{
Console.WriteLine(i.Name);
}
}

3.显示同级节点之前的节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/// <summary>
/// 显示同级结点之前的接点
/// </summary>
static void ShowPrevElement()
{
//根元素
XElement xe = XElement.Load(path);

XElement target = xe.Descendants("SubItem").FirstOrDefault();

//遍历同级前的接点
foreach (var item in target.ElementsBeforeSelf())
{
Console.WriteLine(item.Name);
}
}

4.显示同级节点后面的节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/// <summary>
/// 显示同级结点之后的接点
/// </summary>
static void ShowNextElement()
{
//根元素
XElement xe = XElement.Load(path);

XElement target = xe.Descendants("SubItem").FirstOrDefault();

//遍历同级后的接点
foreach (var item in target.ElementsAfterSelf())
{
Console.WriteLine(item.Name);
}
}

本章总结

课后作业

1>已有整型数组nums包含10个数,完成以下功能:
1.查询大于50的偶数的数量
2.查询所有偶数的平均值
3.查询所有奇数中的最小数
4.查询所有偶数中的最大数
5.查询大于50的所有数字的平均值。
6.查询所有奇数,且降序排序

2>已有学生数组stus,包含10个学生对象(Name,Age,Sex),完成以下功能:
1.查询所有男生的数量
2.查询男生中年龄最大的学生姓名
3.查询女生中年龄最小的学生姓名
4.查询所有已成年的学生的年龄的平均值
5.查询姓“张”的学生人数
6.查询姓“张”的学生中,年龄最大的学生
7.查询姓“张”的学生,且按年龄升序