C#面试题及详细答案120道(51-60)-- LINQ与Lambda
《前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。

文章目录
- 一、本文面试题目录
- 51. 什么是LINQ?LINQ的类型有哪些(LINQ to Objects、LINQ to SQL等)
- 52. LINQ查询表达式与方法语法的区别
- 53. 简述延迟执行(Deferred Execution)和即时执行(Immediate Execution)
- 54. 什么是IQueryable?与IEnumerable的区别
- 55. LINQ中的常见操作符(Where、Select、OrderBy、GroupBy等)的作用
- 56. 如何使用LINQ进行连接查询(Join)?
- 57. 什么是Lambda表达式?其结构是什么?
- 58. LINQ to SQL和Entity Framework的区别
- 59. 如何优化LINQ查询性能?
- 60. 什么是表达式树(Expression Tree)?应用场景是什么?
- 二、120道C#面试题目录列表
一、本文面试题目录
51. 什么是LINQ?LINQ的类型有哪些(LINQ to Objects、LINQ to SQL等)
-
原理说明:
LINQ(Language Integrated Query,语言集成查询)是C#中用于查询数据的统一语法,它将查询能力直接集成到编程语言中,支持对各种数据源(集合、数据库、XML等)使用一致的语法进行查询。
LINQ的核心思想是“将数据查询视为语言的一部分”,无需针对不同数据源学习不同的查询语法(如SQL、XPath等)。 -
常见LINQ类型:
- LINQ to Objects:查询内存中的集合(如
List<T>、Array等)。 - LINQ to SQL:查询关系型数据库(如SQL Server),通过映射将数据库表转换为C#类。
- LINQ to XML:查询和操作XML文档。
- LINQ to Entities:基于Entity Framework查询数据库,是LINQ to SQL的进化版。
- Parallel LINQ (PLINQ):并行查询,利用多核CPU加速查询过程。
- LINQ to Objects:查询内存中的集合(如
-
示例代码:
using System; using System.Linq; using System.Collections.Generic;class Program {static void Main(){// LINQ to Objects示例:查询整数集合中大于5的元素List<int> numbers = new List<int> { 3, 7, 2, 8, 5, 10 };var result = from num in numberswhere num > 5select num;Console.WriteLine("LINQ to Objects结果:");foreach (var num in result){Console.Write(num + " "); // 输出:7 8 10}} }
52. LINQ查询表达式与方法语法的区别
-
原理说明:
LINQ有两种语法形式,两者功能等价,可相互转换:- 查询表达式:类SQL的声明式语法,以
from开头,select或group by结尾,结构清晰,适合复杂查询。 - 方法语法:通过调用扩展方法(如
Where()、Select())实现查询,更简洁,适合简单查询或链式调用。
编译器会将查询表达式自动转换为方法语法执行。
- 查询表达式:类SQL的声明式语法,以
-
区别对比:
特性 查询表达式 方法语法 语法风格 类SQL,声明式 方法调用,链式编程 可读性 复杂查询更易读 简单查询更简洁 适用场景 多表连接、分组、排序等复杂查询 简单过滤、投影等操作 -
示例代码:
// 数据源 List<string> fruits = new List<string> { "apple", "banana", "cherry", "date" };// 1. 查询表达式 var queryExpr = from fruit in fruitswhere fruit.Length > 5orderby fruitselect fruit;// 2. 方法语法(等价于查询表达式) var methodSyntax = fruits.Where(fruit => fruit.Length > 5).OrderBy(fruit => fruit);// 输出结果相同:banana cherry
53. 简述延迟执行(Deferred Execution)和即时执行(Immediate Execution)
-
原理说明:
- 延迟执行:LINQ查询在定义时不会立即执行,而是在首次枚举结果(如
foreach循环、ToList()等)时才执行。这使得查询可以被多次执行,且每次执行都基于数据源的最新状态。 - 即时执行:查询在定义时立即执行,结果被缓存。通常通过调用返回具体结果的方法(如
ToList()、Count())触发。
- 延迟执行:LINQ查询在定义时不会立即执行,而是在首次枚举结果(如
-
关键区别:
- 延迟执行的查询可视为“查询计划”,而非实际结果;即时执行则直接生成结果。
- 延迟执行适合大数据集或需要动态更新数据源的场景;即时执行适合需要立即获取结果并复用的场景。
-
示例代码:
List<int> numbers = new List<int> { 1, 2, 3 };// 延迟执行:查询未立即执行 var deferredQuery = numbers.Where(n => n > 1);// 修改数据源 numbers.Add(4);// 首次枚举时执行查询(结果:2,3,4) foreach (var num in deferredQuery) {Console.Write(num + " "); }// 即时执行:调用ToList()立即执行并缓存结果 var immediateResult = numbers.Where(n => n > 1).ToList(); numbers.Add(5);// 结果不变(仍为2,3,4),因为已缓存 foreach (var num in immediateResult) {Console.Write(num + " "); }
54. 什么是IQueryable?与IEnumerable的区别
-
原理说明:
- IQueryable:继承自
IEnumerable,用于表示可查询的数据源(如数据库),支持将查询转换为底层数据源的查询语言(如SQL),实现远程查询。 - IEnumerable:表示内存中可枚举的集合,查询在本地内存中执行,适用于内存中的数据(如
List<T>)。
- IQueryable:继承自
-
核心区别:
特性 IQueryable IEnumerable 执行位置 远程数据源(如数据库) 本地内存 查询转换 支持转换为SQL等底层语言 不支持,直接在内存中执行 延迟执行 支持(基于表达式树) 支持(基于委托) 适用场景 数据库查询(如EF Core) 内存集合查询(如List) -
示例代码:
using System.Linq; using Microsoft.EntityFrameworkCore;// 假设DbContext中有一个Users表 public class AppDbContext : DbContext {public DbSet<User> Users { get; set; } }class Program {static void Main(){using (var context = new AppDbContext()){// IQueryable:查询在数据库执行(生成SQL:SELECT * FROM Users WHERE Age > 18)IQueryable<User> dbQuery = context.Users.Where(u => u.Age > 18);// IEnumerable:查询在内存中执行(先加载所有数据到内存,再过滤)IEnumerable<User> memoryQuery = context.Users.ToList().Where(u => u.Age > 18);}} }public class User { public int Age { get; set; } }
55. LINQ中的常见操作符(Where、Select、OrderBy、GroupBy等)的作用
-
原理说明:
LINQ操作符是用于构建查询的扩展方法,按功能可分为过滤、投影、排序、分组等类型。 -
常见操作符及作用:
- Where:过滤元素,保留满足条件的元素。
- Select:投影,将元素转换为新的形式(如提取属性或转换为匿名类型)。
- OrderBy/OrderByDescending:按指定键升序/降序排序。
- GroupBy:按指定键分组,返回键值与分组元素的集合。
- Join:连接两个集合(类似SQL的JOIN)。
- Count:返回元素数量(即时执行)。
- First/FirstOrDefault:返回第一个元素(或默认值)。
-
示例代码:
List<Student> students = new List<Student> {new Student { Name = "Alice", Age = 18, Score = 90 },new Student { Name = "Bob", Age = 20, Score = 85 },new Student { Name = "Charlie", Age = 18, Score = 95 } };// Where:筛选年龄大于18的学生 var adults = students.Where(s => s.Age > 18);// Select:提取姓名和分数(投影为匿名类型) var nameScores = students.Select(s => new { s.Name, s.Score });// OrderBy:按分数降序排序 var sortedByScore = students.OrderByDescending(s => s.Score);// GroupBy:按年龄分组 var groupedByAge = students.GroupBy(s => s.Age);public class Student {public string Name { get; set; }public int Age { get; set; }public int Score { get; set; } }
56. 如何使用LINQ进行连接查询(Join)?
-
原理说明:
LINQ的Join操作用于根据两个集合中的共同键连接数据,类似SQL中的内连接(INNER JOIN)。GroupJoin则类似左外连接(LEFT JOIN),保留左集合中未匹配的元素。 -
语法说明:
- 内连接:
from a in 集合A join b in 集合B on a.键 equals b.键 select ... - 左外连接:结合
GroupJoin和DefaultIfEmpty()实现。
- 内连接:
-
示例代码:
// 数据源 List<Student> students = new List<Student> {new Student { Id = 1, Name = "Alice", ClassId = 1 },new Student { Id = 2, Name = "Bob", ClassId = 2 } };List<Class> classes = new List<Class> {new Class { Id = 1, Name = "一班" },new Class { Id = 2, Name = "二班" } };// 1. 内连接:查询学生及其所属班级 var innerJoin = from s in studentsjoin c in classes on s.ClassId equals c.Idselect new { s.Name, ClassName = c.Name }; // 结果:Alice-一班,Bob-二班// 2. 左外连接:查询所有学生(包括无班级的学生) var leftJoin = from s in studentsjoin c in classes on s.ClassId equals c.Id into joinedClassesfrom c in joinedClasses.DefaultIfEmpty() // 无匹配时返回默认值(null)select new { s.Name, ClassName = c?.Name ?? "无班级" };public class Student { public int Id { get; set; } public string Name { get; set; } public int ClassId { get; set; } } public class Class { public int Id { get; set; } public string Name { get; set; } }
57. 什么是Lambda表达式?其结构是什么?
-
原理说明:
Lambda表达式是一种简洁的匿名函数写法,可用于定义委托或表达式树,广泛应用于LINQ、事件等场景。其核心是“输入参数 => 表达式或语句块”。 -
结构:
- 参数列表:零个或多个参数,若单个参数可省略括号,无参数用
()表示。 - Lambda运算符:
=>(读作“goes to”)。 - 主体:表达式(返回值类型自动推断)或语句块(需显式
return)。
- 参数列表:零个或多个参数,若单个参数可省略括号,无参数用
-
示例代码:
// 1. 无参数,返回常量 Func<string> greet = () => "Hello"; Console.WriteLine(greet()); // 输出:Hello// 2. 单个参数(省略括号) Func<int, int> square = x => x * x; Console.WriteLine(square(5)); // 输出:25// 3. 多个参数 Func<int, int, int> add = (a, b) => a + b; Console.WriteLine(add(3, 4)); // 输出:7// 4. 语句块主体(需显式return) Func<int, string> checkEven = num => {if (num % 2 == 0)return "偶数";elsereturn "奇数"; }; Console.WriteLine(checkEven(7)); // 输出:奇数
58. LINQ to SQL和Entity Framework的区别
-
原理说明:
两者均为微软的ORM(对象关系映射)技术,用于将C#对象与数据库表映射,但定位和功能不同:- LINQ to SQL:轻量级ORM,仅支持SQL Server,功能简单,已逐渐被淘汰。
- Entity Framework (EF):功能更强大的ORM,支持多数据库(SQL Server、MySQL等),提供Code First、Database First等开发模式,是LINQ to SQL的替代者。
-
核心区别:
特性 LINQ to SQL Entity Framework 数据库支持 仅SQL Server 多数据库(SQL Server、MySQL等) 模型灵活性 仅支持表到类的映射 支持复杂模型(继承、关联等) 开发模式 仅Database First Code First、Database First、Model First 扩展性 较弱 强(可自定义映射、拦截器等) 现状 已停止更新 持续维护(如EF Core) -
示例代码:
// LINQ to SQL示例(需手动创建DataContext) public class SchoolDataContext : System.Data.Linq.DataContext {public SchoolDataContext(string connectionString) : base(connectionString) { }public System.Data.Linq.Table<Student> Students { get; set; } }// Entity Framework示例(EF Core) public class SchoolDbContext : DbContext {public DbSet<Student> Students { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer("连接字符串"); }
59. 如何优化LINQ查询性能?
-
原理说明:
LINQ查询性能受数据源类型、查询复杂度、执行时机等因素影响,优化目标是减少不必要的计算和数据传输。 -
优化方法:
- 使用IQueryable而非IEnumerable:对数据库查询,
IQueryable可将过滤逻辑转换为SQL,减少内存加载的数据量。 - 延迟执行与即时执行结合:避免过早调用
ToList(),只在需要时加载数据。 - 减少返回字段:使用
Select投影必要字段,而非返回整个对象。 - 避免N+1查询问题:使用
Include()预加载关联数据(EF Core中)。 - 合理使用索引:对查询频繁的字段在数据库中创建索引。
- 分页查询:使用
Skip()和Take()减少一次性加载的数据量。
- 使用IQueryable而非IEnumerable:对数据库查询,
-
示例代码:
using Microsoft.EntityFrameworkCore;// 反例:IEnumerable导致全表加载后过滤 var badQuery = context.Users.ToList().Where(u => u.Age > 18); // 先加载所有用户// 正例:IQueryable在数据库中过滤 var goodQuery = context.Users.Where(u => u.Age > 18); // 仅加载符合条件的用户// 优化:只返回必要字段 var projectedQuery = context.Users.Where(u => u.Age > 18).Select(u => new { u.Name, u.Email }); // 仅查询Name和Email// 优化:预加载关联数据(避免N+1问题) var withInclude = context.Users.Include(u => u.Orders) // 一次性加载用户及其订单.Where(u => u.Age > 18);// 分页查询 int pageSize = 10; int pageNumber = 1; var paginated = context.Users.Skip((pageNumber - 1) * pageSize).Take(pageSize);
60. 什么是表达式树(Expression Tree)?应用场景是什么?
-
原理说明:
表达式树是一种数据结构,用于表示代码表达式的语法结构(如变量、运算符、方法调用等)。它将代码转换为可遍历、修改的对象树,而非直接编译为可执行代码。 -
核心特性:
- 可在运行时解析和修改表达式逻辑。
- 常用于将C#表达式转换为其他语言(如SQL)。
-
应用场景:
- LINQ to Entities:将Lambda表达式转换为SQL查询。
- 动态查询构建:在运行时动态生成查询条件。
- ORM框架:映射对象操作到数据库操作。
-
示例代码:
using System; using System.Linq.Expressions;class Program {static void Main(){// 构建表达式树:(x, y) => x + yParameterExpression x = Expression.Parameter(typeof(int), "x");ParameterExpression y = Expression.Parameter(typeof(int), "y");BinaryExpression add = Expression.Add(x, y);Expression<Func<int, int, int>> addExpr = Expression.Lambda<Func<int, int, int>>(add, x, y);// 编译表达式树为委托并执行Func<int, int, int> addFunc = addExpr.Compile();Console.WriteLine(addFunc(3, 5)); // 输出:8// 解析表达式树(打印表达式结构)Console.WriteLine(addExpr.Body.ToString()); // 输出:(x + y)} }上述示例中,表达式树
addExpr表示x + y的逻辑,可在运行时解析其结构,或编译为委托执行。
二、120道C#面试题目录列表
| 文章序号 | C#面试题120道 |
|---|---|
| 1 | C#面试题及详细答案120道(01-10) |
| 2 | C#面试题及详细答案120道(11-20) |
| 3 | C#面试题及详细答案120道(21-30) |
| 4 | C#面试题及详细答案120道(31-40) |
| 5 | C#面试题及详细答案120道(41-50) |
| 6 | C#面试题及详细答案120道(51-60) |
| 7 | C#面试题及详细答案120道(61-75) |
| 8 | C#面试题及详细答案120道(76-85) |
| 9 | C#面试题及详细答案120道(86-95) |
| 10 | C#面试题及详细答案120道(96-105) |
| 11 | C#面试题及详细答案120道(106-115) |
| 12 | C#面试题及详细答案120道(116-120) |
