从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);
}

总结

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

原文地址:https://www.cnblogs.com/WilsonPan/p/2939610.html