Linq

作者: 天堂迈舞 | 来源:发表于2016-02-03 22:52 被阅读59次

Enumerable Where Select

Linq 读作 link 语言集成查询(Language Integrated Query),让我们可以像操作数据库那样操作内存数据。它有个特点,在使用时执行
如何在使用时获取数据,就要用到一个关键字yield,使用时和return一起出现。

先看个例子

        static void Main(string[] args)
        {
            foreach (var item in GenerateStrings())
            {
                Console.WriteLine(item.ToString());
            }
        }
        static IEnumerable<string> GenerateStrings()
        {
            for (int i = 0; i < 10; i++)
            {
                yield return i.ToString();
            }
        }

在foreach的数据源中,调用这个方法。在输出那设一个断点,单步执行,可以看到,数据源并不是在方法执行完成后再返回到foreach中,而是每调用到下一个数据时,在方法中获得下一个数据。这就是yield return.
这种做法有什么好处?在需要的时候调用,数据只在需要用到的时候调入内存,而不是把整个集合都调入内存,节省存储空间,在这个例子里其实并不能很好的体现好嘛。

        static void Main(string[] args)
        {
            var sequence = GenerateStrings();//==①
            sequence = sequence.Where(x => x.Length < 2);//==②    x => x.Length < 2//==⑤
            foreach (var item in sequence)//==③
            {
                Console.WriteLine(item.ToString());//==⑥
            }
        }
        static IEnumerable<string> GenerateStrings()//==④
        {
            for (int i = 8; i < 100; i++)
            {
                yield return i.ToString();
            }
        }

在遇到第①,②句时,并没有进到 GenerateStrings其中,而是遇到foreach时,依次进到GenerateStrings中,取到返回值后,再判断⑤子句,成立后才会输出。
但我在调试的时候明明没有进到GenerateStrings,他就已经有结果了,不懂。

再看一个,我们自己写一个扩展方法,功能同上一个的where子句

    public static class MyLinq
    {
        //一个扩展方法
        public static IEnumerable<string> MyWhere(this IEnumerable<string> source)
        {
            foreach (string item in source)
            {
                if (item.Length < 2)
                    yield return item;
            }
        }
    }
    class Program
    {

        static void Main(string[] args)
        {
            var sequence = GenerateStrings();
            sequence = sequence.Where(x => x.Length < 2);
            var sequence2 = GenerateStrings();
            sequence2 = sequence2.MyWhere();
            foreach (var item in sequence)
            {
                Console.WriteLine(item.ToString());
            }
            foreach (var item in sequence2)
            {
                Console.WriteLine(item.ToString());
            }
            Console.ReadKey();
        }
        static IEnumerable<string> GenerateStrings()
        {
            for (int i = 8; i < 100; i++)
            {
                yield return i.ToString();
            }
        }

    }

输出都是一样的
8
9
8
9

介绍一下第二个foreach的执行过程
遇到sequence2 = sequence2.MyWhere();时是先不执行的
在foreach到的时候才会执行MyWhere
到MyWhere中的foreach后,需要一个数据源
那么就去执行var sequence2 = GenerateStrings()
依次的获取数据,拿到一个8后,判断长度是否小于2,满足,返回8,输出。
9也是一样
到10的时候,判断不小于2
重复获取数据,判断,直到99,没有了,退出。

下面改一下那个扩展方法

 public static IEnumerable<string> MyWhere(this IEnumerable<string> source,Func<string,bool> predicate)
        {
            foreach (string item in source)
            {
                if (predicate(item))
                    yield return item;
            }
        }

还有这里
sequence2 = sequence2.MyWhere(x=>x.Length<2);

这样以后,我们的扩展方法就更加灵活,功能上和C#提供的Where就一样了。后面是一个委托,用来判断条件,返回一个bool值,在if里判断。
再牛逼一点,把我们的MyWhere变成一个泛型方法

public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> source, Func<T, bool> predicate)
        {
            foreach (T item in source)
            {
                if (predicate(item))
                    yield return item;
            }
        }

改完这个,主函数里是不用动的,泛型大法好。会玩的你知道下一步怎么玩了么?

        static IEnumerable<int> GenerateIntegers()
        {
            for (int i = 8; i < 100; i++)
            {
                yield return i;
            }
        }

写个返回整数的方法咯。
var sequence3 = GenerateIntegers().MyWhere(x => x % 7 == 0);
这个就可以拿到所有7的倍数啦。
但是要注意到,我们刚才那个泛型方法没有任何错误检查机制,所以…

下面是select

select就比较简单了
var sequence4 = GenerateIntegers().Select(x => x.ToString());
var sequence5 = GenerateIntegers().Select(x =>true);
自己感受一下select后面的lambda表达式

如果,我们来重写一下这个select

        public static IEnumerable<string> MySelect(this IEnumerable<int> source,Func<int,string> selector)
        {
            foreach (int item in source)
            {
                yield return selector(item);
            }
        }

像这样
var sequence4 = GenerateIntegers().MySelect(x => x.ToString());
感受一下,结果是一样的。
那么我们又可以写个泛型扩展方法了

        public static IEnumerable<TResult> MySelect<TSource,TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
        {
            foreach (TSource item in source)
            {
                yield return selector(item);
            }
        }

其实select 有一个重载的版本是可以获取索引的

            var sequence6 = GenerateIntegers().Select((x,index)=>new { index, str=x.ToString()+"str" });
            foreach (var s in sequence6)
            {
                Console.WriteLine("{0}=={1}", s.index, s.str);
            }

借助一个匿名类型,我们可以同时得到索引和内容。

相关文章

  • LINQ

    什么是linq? linq是语言集成查询。 linq主要包含三部分 linq to xml linq to obj...

  • Linq用法笔记

    一、什么是Linq? LINQ即Language Integrated Query(语言集成查询),LINQ是集成...

  • Lession12-LINQ

    LINQ简介 编写一个扩展方法 LINQ查询方法 LINQ查询的延迟加载 Linq标准查询操作符 LinqToXML

  • LINQ入门

    linq是语言集成查询。 linq to object :面向对象的查询。 linq to xml:针对xml查询...

  • (转).NET面试题系列[14] - LINQ to SQL与I

    LINQ to Object和LINQ to SQL有何区别? LINQ to SQL可以将查询表达式转换为SQL...

  • linq语句

    https://www.yiibai.com/linq/linq_filtering_operators.html...

  • EF Core 备忘

    模糊查询sql linq 内连接查询sql linq 左连接查询sql linq 左连接查询(连接内带条件)sql...

  • 四.SolidWorks 开发之Linq初探

    SolidWorks开发之Linq初探 一.何为Linq 语言集成查询(英语:Language Integrate...

  • Lambad 和Linq多表连查

    Lamdad Linq

  • 在 UiPath 中使用 LINQ

    在《LINQ 让数据操作更简单》一文中,我简单地介绍了 LINQ 是什么,以及它可以做什么。总的来说,LINQ 是...

网友评论

      本文标题:Linq

      本文链接:https://www.haomeiwen.com/subject/tseekttx.html