Unity3D C#中使用LINQ查询(与 SQL的区别)
Why
项目中有要用到 xml 读取,使用C#的原始XML来写非常麻烦,但是使用Linq to XML来写就相对简洁的多
优点:C#把大量行为压缩到几行代码中,可以用很少的代码完成复杂的工作
缺点:性能相对不高。for手写代码比用LINQ代码速度快十几倍(网友测试结论)
LINQ在平时的开发中很少见,主要是因为这个东西性能敏感,在游戏逻辑开发中,要慎用。最常见的使用方式是在做编辑器功能时候,配合反射一起使用。
其中慎用的原因是LINQ 在执行过程中会产生一些临时变量,而且会用到委托(lambda 表达式),所以会产生一定的垃圾内存从而影响 Unity 的运行时效率,这就是建议大家尽量在 Unity 中少用 LINQ 的原因。
LINQ理念是函数式编程。
What
LINQ是什么原理呢
首先,需要循环处理整个对象
然后,将每个值与where条件作比较
最后,收集结果储存在代码中以供使用
这里根据我自己的理解给出一个公式:
LINQ = 集合 + 操作符 + 具体操作
- 集合:C# 中的 Array、Dictionary、List、Stack、Queue 都是集合,都是可以用 LINQ 的。
- 操作符: Where、Select、GroupBy、Distinct 都是操作符。
- 操作:操作指的是foreach/ForEach/Single/First/ToList/ToDictionary/ToHashSet等等
之前一直对LINQ这个概念了解不够多,平时写gameplay逻辑的时候也几乎用不到这块的知识,最近在做编辑器相关功能的时候有些疑问,翻看了很多框架里都有使用到LINQ,所以这篇文章主要是对游戏开发中使用LINQ的一些理解。
1.内容概述
- 基本概念
- 使用方式
- 自己的理解
- 底层相关
- 动手实现一个操作符
2.基本概念
语言集成查询(英语:Language Integrated Query,:LINQ),发音"link"。
我个人而言更喜欢叫它查询表达式,因为它主要做的一个事情就是对数据集合的查询。
LINQ的代码大概是这个样子(截取自一段编辑器代码)
mModules = editorAssembly
.GetTypes()
.Where(type => moduleType.IsAssignableFrom(type) && !type.IsAbstract)
.Select(type => type.GetConstructors().First().Invoke(null))
.Cast<IEditorPlatformModule>()
.ToList();
基本上就是对集合进行各种过滤和遍历处理,如果把以上的代码用 for 循环去写会变成如下:
foreach (var type in editorAssembly.GetTypes())
{
if (moduleType.IsAssignableFrom(type) && !type.IsAbstract)
{
var instance = type.GetConstructors().First().Invoke(null) as IEditorPlatformModule;
mModules.Add(instance);
}
}
这里可以看到,虽然都可以完成相同的功能,但是使用LINQ可以给我们带来不同的编程体验,提升我们开发效率和代码品味,并且让结构层次更清晰。
How
先展示一下基本的使用场景
public class LINQExample : MonoBehaviour
{
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
void Start()
{
var students = new List<Student>()
{
new Student() {Name = "托儿索", Age = 18},
new Student() {Name = "儿童劫", Age = 16},
new Student() {Name = "小学僧", Age = 17},
new Student() {Name = "娃娃鱼", Age = 18}
};
// 1.基本的遍历
students.ForEach(s => Debug.Log(s.Name));
// 2.基本的条件过滤(Age > 5)
students.Where(s => s.Age > 5)
.ToList()
.ForEach(s => Debug.Log(s.Name));
// 与以上代码等价
(from s in students
where s.Age > 5
select s)
.ToList()
.ForEach(s => Debug.Log(s.Name));
// 3.基本的变换(student 转换成 name)
students.Select(s => s.Name)
.ToList()
.ForEach(name => Debug.Log(name));
// 与以上代码等价
(from s in students
select s.Name)
.ToList()
.ForEach(name => Debug.Log(name));
// 4.基本的分组(使用学生的名字分组)
students.GroupBy(s => s.Name)
.ToList()
.ForEach(group => Debug.Log(group.Count()));
// 与以上代码等价
(from s in students
group s by s.Name)
.ToList()
.ForEach(group => Debug.Log(group.Count()));
// 等等
}
}
有些经验的程序猿应该可以看出,LINQ理念是函数式编程。
这里根据我自己的理解给出一个公式:
LINQ = 集合 + 操作符 + 具体操作
- 集合:C# 中的 Array、Dictionary、List、Stack、Queue 都是集合,都是可以用 LINQ 的。
- 操作符: Where、Select、GroupBy、Distinct 都是操作符。
- 操作:操作指的是foreach/ForEach/Single/First/ToList/ToDictionary/ToHashSet等等
有过开发经验的应该都可以理解集合和具体操作是什么,这个公式中平时接触最少的也就只有操作符了。
关于都有什么操作符和每个操作符如何使用,可以参考微软的官方文档:
最后如果对于如何使用LINQ还有有疑问的地方,可以翻阅一下C#官方文档的LINQ部分:
7.总结
其实我觉得理解LINQ的核心就是这个公式:
LINQ = 集合 + 操作符 + 具体操作
当理解了这个公式之后,要做的也就是不断的积累公式中包含的API的使用。
关于都有什么API以及如何使用,微软的官方文档已经写的比较清楚,上面也给出了链接。
LINQ的主要用途是处理数据,虽然在平时的开发中很少用到,但LINQ的使用会变成我们的一项能力,某些框架也是以LINQ为基础,所以还是建议掌握。
前言:
学过SQL的一看就懂
LINQ代码很直观
但是,LINQ却又跟SQL完全不同
首先来看一下调用LINQ的代码
int[] badgers = {36,5,91,3,41,69,8};
var skunks =
from pigeon in badgers
where (pigeon != 36 && pigeon <50)
orderby pigeon descending
select pigeon + 5;
var bears = skunks.Take(3);
Debug.Log("Get your kicks on route {0}",weasels.Sum());
LINQ与SQL最大的不同
就在于SQL查询的是数据库表,而LINQ查询的是对象
也就是说,SQL查询的是集合,而LINQ查询的是可以储存的任何内容,可以是值、struct、对象等。
这就形成了最大的区别:SQL表没有顺序,而LINQ查询的内容是有顺序的
从代码行的不同
SQL语句把SELECT放在第一句
而LINQ将SELECT放在了最后一句
两者同样具有where,orderby等语句
LINQ并不只是查询并获取数据项
LINQ还提供了管理数据所需要的各种工具
例如上面代码的 select pigeon + 5;
作用为将每个数字加5后输出
类似地,还有LINQ定义的一些方法,如Count(),Min(),Max(),Sum(),Average()等
注意:
LINQ查询会有“延迟计算”
也就是说,访问LINQ查询的结果之前并不会真正运行LINQ查询
这算是一种性能机制
当然,也可以使用ToList()告诉LINQ立即执行查询
性能比较
- 当集合是來自不确定个数的IEnumerable时,请使用 Any().
- 当集合是來自外部数据(ex: LINQto SQL, LINQ to Entities)时,请使用 Any().
- 当集合是來自 .NET Framework 內建的集合时,请使用Count().
引用:
关于C# 扩展方法: