使用Linq扩展方法时容易忽略的小问题

时间:2021-06-26 15:43:47

问题重现

下面直接给出用于说明文章主题的完整代码。

//************************************************************    
//
// Linq扩展方法示例代码
//
// Author:三五月儿
//
// Date:2014/10/01
//
// http://blog.csdn.net/yl2isoft
//
//************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqExtendFunctionExp
{
class Program
{
static void Main(string[] args)
{
List<Student> studentList = new List<Student>();
studentList.Add(new Student() { Id = 1, Name = "ZhangSan", ClassId = 1, Score = 85});
studentList.Add(new Student() { Id = 2, Name = "LiSi" , ClassId = 2, Score = 76});
studentList.Add(new Student() { Id = 3, Name = "WangWu" , ClassId = 1, Score = 89});
studentList.Add(new Student() { Id = 4, Name = "ZhaoLiu", ClassId = 2, Score = 91 });
studentList.Add(new Student() { Id = 5, Name = "LiuJian" , ClassId = 1, Score = 78});
studentList.Add(new Student() { Id = 6, Name = "WuBin", ClassId = 2, Score = 67 });
var handledStudentList = studentList.GroupBy(it => it.ClassId).OrderBy(it => it.Max(p => p.Score)).ToList();
foreach (var students in handledStudentList)
{
foreach(var student in students)
{
if (student.Score < 85)
{
student.Name = "不合格";
}
}
}
foreach (var s in studentList)
{
Console.WriteLine("Id = {0}, Name = {1}, ClassId = {2}, Score = {3}", s.Id, s.Name, s.ClassId, s.Score);
}
}
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int ClassId { get; set; }
public int Score { get; set; }
}
}
代码主要完成的工作是:

(1)定义学生对象集合studentList;

(2)使用Linq扩展方法对studentList集合进行分组和排序操作得到集合handledStudentList;

(3)遍历handledStudentList集合中的学生对象,当学生的成绩低于85时,修改该学生的姓名为“不合格”;

(4)输出studentList集合中所有学生的信息。

本文需要探讨的问题是:

在操作(4)中输出studentList集合学生信息时,Id为2,5,6的学生成绩低于85分,那么这些学生的姓名会被显示成“不合格”吗?

你可能会说不会,同时给出你的原因:

因为将学生姓名修改为“不合格”的操作是在遍历handledStudentList集合时完成的,因此修改的是handledStudentList集合中的学生信息,所以输出studentList集合中学生信息时不会受此影响。

但是,实际情况会是这样吗?请看代码的执行结果。

使用Linq扩展方法时容易忽略的小问题 

图1 代码运行结果

从图1可以了解到:学号为2,5,6的学生姓名被修改为了“不合格”,原因出在哪里呢?

 

问题分析

下面以扩展方法GroupBy为例来对问题进行分析,使用Linq中其他扩展方法的情况与使用扩展方法GroupBy的情况类似。

扩展方法GroupBy的作用是:按照指定的条件对集合进行分组操作,返回一个GroupedEnumerable类型的对象,在返回的对象内部仍然持有被分组集合的引用,所以,当我们操作分组后的集合时其实操作的仍然是分组前的集合对象。正因为此,才出现了本文前面描述的现象。

对于这点,是不是很容易被忽视啊,因为明明返回了一个新类型的对象,谁会想到,在它内部还持有被处理集合的引用呢。

好吧,希望大家在以后使用Linq的扩展方法时能注意这点。

至于GroupBy方法为什么会这样实现,那就得去研究GroupBy方法的源码了,等到以后有时间再说吧,这里只是想提出这样一个问题供大家参考,以免因为不知道这个知识点而出现一些本不应该出现的小问题。

好了,88。