zoukankan      html  css  js  c++  java
  • 从IL认识关键字(五)

    关键字

       上一篇研究了lock关键字,最后一篇讨论一下Linq的关键字,对于Linq存在的争议院子里老赵的一篇文章已经解释过,这里以Linq To Objects来看Linq关键字。Linq定义了很多关键字,这里只列举其中的where orderby groupby select关键字,其他关键字用到也是相同道理。

    MSDN解释

      语言集成查询 ( Language INtegrated Query ) 是一组技术的名称,这些技术建立在将查询功能直接集成到 C# 语言(以及 Visual Basic 和可能的任何其他 .NET 语言)的基础上。借助于 LINQ,查询现在已是高级语言构造,就如同类、方法、事件等等。

     从MSDN上看,Linq究竟是什么,我是没看明白。还是老老实实写代码反编译看看。

    Code And IL

       下面定义一个数组,先从简单的where条件开始看

    private static int[] nums = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    static void Main(string[] args)
    {
        var result = from num in nums
                 where num > 5
                 select num;
    
        Console.Read();
    }

       利用Reflector反编译上面代码,得出下面IL:

    .method private hidebysig static void Main(string[] args) cil managed
    {
        .entrypoint
        .maxstack 4
        .locals init (
            [0] class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> enumerable)
        L_0000: nop 
        L_0001: ldsfld int32[] Test.Program::nums
        L_0006: ldsfld class [mscorlib]System.Func`2<int32, bool> Test.Program::CS$<>9__CachedAnonymousMethodDelegate1
        L_000b: brtrue.s L_0020
        L_000d: ldnull 
        L_000e: ldftn bool Test.Program::<Main>b__0(int32)
        L_0014: newobj instance void [mscorlib]System.Func`2<int32, bool>::.ctor(object, native int)
        L_0019: stsfld class [mscorlib]System.Func`2<int32, bool> Test.Program::CS$<>9__CachedAnonymousMethodDelegate1
        L_001e: br.s L_0020
        L_0020: ldsfld class [mscorlib]System.Func`2<int32, bool> Test.Program::CS$<>9__CachedAnonymousMethodDelegate1
        L_0025: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<int32>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>)
        L_002a: stloc.0 
        L_002b: call int32 [mscorlib]System.Console::Read()
        L_0030: pop 
        L_0031: ret 
    }

       上面标红的的两个对象(一个委托,一个函数),这是编译器自己生成的,这段IL也简单

    1. 判断委托(CS$<>9__CachedAnonymousMethodDelegate1)是否为空,若为空创建一个<Main>b_0函数的委托
    2. 调用System.Linq.Enumerable.Where<int>(CS$<>9__CachedAnonymousMethodDelegate1)函数
    3. 将结果赋值局部变量enumerable

       翻译成C# Code如下面,由于编译器的生成的名称太长,也不能通过编译,所以将名称改了一下CS$<>9__CachedAnonymousMethodDelegate1  => _delegate    <Main>b_0  => b_0

    private static Func<int,bool> _delegate = null;
    static void Code()
    {
        if (_delegate == null)
        {
            _delegate = new Func<int,bool>(b_0);
        }
        IEnumerable<int> enumerable = System.Linq.Enumerable.Where(nums,_delegate);
    }
    static bool b_0(int n)
    {
        return n > 5;
    }

      将两段代码放在一起,便能看出其中的奥秘。

      

      从上面代码可以看出,Linq语法最终转换成System.Linq.Enumerable.Where(nums,_delegate)的调用,where 条件后面带返回值true,实际上where条件转换委托,select决定IEnumerable<T>的返回值,实际上若select返回不是from 的 Item,将调用System.Linq.Enumerable.Select(TSource,TResult)返回相应对象。

      根据这个例子猜测,实际上Linq的语法最终通过编译器,生成需要的对象,调用System.Linq.Enumerable里面的的扩展方法。当然这里说的都是Framework里面的集合,对象。我们也可以扩展自己的Linq。下面试一个复杂一点的Linq语句(where + orderby),我们猜想orderby应该也有相应的扩展函数,调用顺序应该先调用where筛选数据,然后排序

    复杂一点的Linq

    private static int[] nums = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    static void Main(string[] args)
    {
        var result = from num in nums
                 where num > 5
                 orderby num.ToString().Substring(0)
                 select num;
    
        Console.Read();
    }

      这里不把IL贴出来,大家可以自己反编译看看,下面直接把将IL翻译的Code

    private static Func<int,bool> _delegate = null;
    private static Func<int,string> _delegate1 = null;
    static void Code()
    {
        if (_delegate == null)
        {
            _delegate = new Func<int,bool>(b_0);
        }
        if(_delegate1 == null)
        {
            _delegate1 = new Func<int,string>(b_1);
        }
        IEnumerable<int> enumerable = Enumerable.OrderBy(Enumerable.Where(nums,_delegate),_delegate1);
    }
    static bool b_0(int n)
    {
        return n > 5;
    }
    static string b_1(int n)
    {
        return n.ToString().Substring(0);
    }

      这里可以看出,orderby又生成了一个对应的委托。orderby内部实现,通过调用数据源的Sort函数排序,这里就是Array.Sort排序,即快速排序。

    自己的Linq

    View Code
    public class MyLinq<T> : IEnumerable<T>,IEnumerator<T>
    {
        T[] array = new T[10];
        T current;
        int index = 0;
        #region IEnumerable<T> 成员
    
        public IEnumerator<T> GetEnumerator()
        {
            return this;
        }
        #endregion
    
        #region IEnumerable 成员
    
        IEnumerator IEnumerable.GetEnumerator()
        {
           return this;
        }
    
        #endregion
    
        #region IEnumerator<T> 成员
    
        public T Current
        {
            get { return current; }
        }
    
        #endregion
    
        #region IDisposable 成员
    
        public void Dispose()
        {
            
        }
    
        #endregion
    
        #region IEnumerator 成员
    
        object IEnumerator.Current
        {
            get { return current; }
        }
    
        public bool MoveNext()
        {
            if(index < array.Length)
            {
            this.current = array[index++];
            return true;
            }
            return false;
        }
    
        public void Reset()
        {
            this.index = 0;
        }
    
        #endregion
    }

     调用代码

    MyLinq<int> ml = new MyLinq<int>();
    var result = from m in ml
                 select m;
    
    foreach(var item in result)
    {
        Console.WriteLine(item);
    }

    总结

       终于算写完这个系列,最后一篇拖了很久,因为中间有事忙,还小病了一场。第一次写一个系列,虽然不是什么高深的技术,只是把自己平时没注意,没去深挖的的知识去走一遍。总的来说,收获还是不少。还会坚持写博客,算是记录下自己学习的过程。

  • 相关阅读:
    用实例来说明linux命令sort的用法
    shell 编程入门
    VMware sphere的使用
    linux进阶
    Windows系统下的TCP参数优化
    RFID Technology(上)——简介、市场应用与前景、工作原理
    RFID Technology(下)——面临的风险、安全与隐私策略
    TCP连接的状态与关闭方式,及其对Server与Client的影响
    Java Map遍历方式的选择
    博客处女贴
  • 原文地址:https://www.cnblogs.com/WilsonPan/p/2939610.html
Copyright © 2011-2022 走看看