Unity3D C#中使用LINQ查询(与 SQL的区别)

235 篇文章 23 订阅

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等等

有过开发经验的应该都可以理解集合和具体操作是什么,这个公式中平时接触最少的也就只有操作符了。

关于都有什么操作符和每个操作符如何使用,可以参考微软的官方文档:

Enumerable.Aggregate Method (System.Linq)​docs.microsoft.com

最后如果对于如何使用LINQ还有有疑问的地方,可以翻阅一下C#官方文档的LINQ部分:

C# 中的语言集成查询 (LINQ)​docs.microsoft.com

 

 

7.总结

其实我觉得理解LINQ的核心就是这个公式:

LINQ = 集合 + 操作符 + 具体操作

当理解了这个公式之后,要做的也就是不断的积累公式中包含的API的使用。

关于都有什么API以及如何使用,微软的官方文档已经写的比较清楚,上面也给出了链接。

LINQ的主要用途是处理数据,虽然在平时的开发中很少用到,但LINQ的使用会变成我们的一项能力,某些框架也是以LINQ为基础,所以还是建议掌握。

 

使用LINQ查询(与 SQL的区别)

前言:

学过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立即执行查询

 

性能比较

https://blog.csdn.net/caesarliu1121/article/details/24775249

  • 当集合是來自不确定个数的IEnumerable<T>时,请使用 Any().
  • 当集合是來自外部数据 (ex: LINQto SQL, LINQ to Entities) 时,请使用 Any().
  • 当集合是來自 .NET Framework 內建的集合时,请使用 Count() .

 

 

引用:

https://zhuanlan.zhihu.com/p/161681422

https://www.cnblogs.com/fws94/p/6693535.html

 

关于C# 扩展方法: https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值