zoukankan      html  css  js  c++  java
  • Linq基础必备

    1.linq基础必备之对象初始化器和匿名类型因果分析   3.

    一:对象初始化器 

      1.就是在new的时候给公共属性赋值的一种方式

      2. 在没有初始化器之前的时候,我们是怎么初始化的呢???

      1. 构造函数初始化。。。

      public Student(string Name, int Age)
      {
        this.Name = Name;
        this.Age = Age;
      }

      public Student(string Name):this(Name,default(int))
      {

      }

      2. 一个一个的赋值。。。

        var student = new Student();

        student.Name = "jack";
        student.Age = 20;

      3. 为什么要使用初始化器,有一个本质性的原因是什么???【匿名类型】

        var person = new { Name = "jack", Age = 20 };

        可以看到,其实对象初始化器也是为linq而生。

      二:探索匿名类型

      1.查看MSIL的中间代码

        .class private auto ansi sealed beforefieldinit '<>f__AnonymousType0`2'<'<Name>j__TPar','<Age>j__TPar'>
        extends [mscorlib]System.Object

        《1》 .class private auto ansi sealed 说明是私有的密封的类。

        《2》 '<>f__AnonymousType0`2'<'<Name>j__TPar','<Age>j__TPar'> 类名

        《2》 extends [mscorlib]System.Object 可以看到“:”其实就是语法糖,匿名类型都是继承自System.Object

      2. 我们看被重写的equals方法是采用逐值比较的模式判断是否相等。

        《1》 我们要知道类名的生成大概手段 '<>f__AnonymousType0`2'<'<Name>j__TPar','<Age>j__TPar'>

        '<>f__AnonymousType1`3'<'<Name>j__TPar','<Age>j__TPar','<Say>j__TPar'>

        《2》 equals采用的是逐值比较

      3. 匿名类中的属性是只读的。 IL中只有GET,没有SET。

    2.linq基础必备之扩展方法  4.

    一:扩展方法

      使用 this

      《1》 先上代码

      namespace ConsoleApplication1
      {
        class Program
        {
          static void Main(string[] args)
          {
            var str = "12345";

            var result = str.SayLength();
        }
      }

      public static class Extension
      {
        public static int SayLength(this string str)
        {
          return str.Length;
        }
      }

      }

    二:如果说“没有扩展方法”,这个世界会是什么样子???

      1. 包装类 【在原有的福利上享受新福利】 【不能被继承】的类的扩展

      class Program
      {
        static void Main(string[] args)
        {
          //var str = "12345";

          //var result = str.SayLength();

          StrExtenstion str = new StrExtenstion();

          str.Str = "12345";

          var result = str.SayLength();
        }
      }

      public class StrExtenstion
      {
        //原有的福利
        public string Str { get; set; }

        //附加的福利
        public int SayLength()
        {
          return Str.Length;
        }
      }

      如果上面的例子不是很明显,可以看看FCL中的包装类。 List => array

      List源码初探

      1.
      private T[] _items;

      public List()
      {
        this._items = List<T>._emptyArray;
      }

      2. 继承扩展

        FCL中到处都是继承扩展,子类可以享受父类的的福利,并且子类还有独自的附加福利。

        继承链太多,导致很难管理和调试。

      3. 我既能享受类似继承的语法形式,也能对方法进行扩展。 那这个就是“扩展方法”

    三:扩展方法如何定义

      1. 静态类 +静态方法

      2. 方法的第一个参数叫做“数据源”。也就是扩展方法要依附到谁之上???? 【this string/object str】

      3. 扩展方法要注意的地方。

        很多专家说,能不用扩展方法就不要用。担心的就是【方法冲突/覆盖】

        一定要知道扩展方法是后娘养的,所以说它不如亲生的重要,也就是说不是一等公民。

        比如说我在.net 3.5 上定义了一个SayLength方法,如果版本升级到4.0的时候,FCL给string增加了一个SayLength

        方法,这时候代码就会出问题,因为我们的扩展SayLength被4.0的SayLength所覆盖,也就导致了bug的产生。

    四:linq之扩展方法

      linq其实就是在扩展方法上面玩的lambda表达式。

      1. linq所玩的扩展方法在哪里???

      通过F12,我们发现在System.Linq命名空间之下。

      public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func);

      =>

      public static string Aggregate(this IEnumerable source, Func func);

      加上泛型之后,就是一个算法的重用。

    3.Linq基础必备之yield词法及IEnumerable,GetEnumerator的MSIL分析  5.

    一:linq基础必备IEnumerable,IEnumerator
    linq查询必须的集合必须要实现这两个接口。
    《1》 IEnumerable
    GetEnumerator方法
    《2》 Current 和MoveNext()属性, Reset方法
    二:迭代的基础
    1. 因为有了这IEnumerable,IEnumerator接口,我们的集合才可以迭代,可以迭代,我们就可以使用select词法和select扩展方法
    2. foreach语法糖
    谁知道foreach的MSIL是什么???
    《1》 深刻认识foreach这个语法糖
    .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<int32> nums,
    [1] class [mscorlib]System.Collections.Generic.List`1<int32> V_1,
    [2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> V_2,
    [3] int32 num)

    我们发现,多了一个临时变量,是一个Enumerator<int32>类型变量 V_2
    var nums = new List<int>() { 1, 2 };
    var MyEnumerator = nums.GetEnumerator();
    try
    {
    while (MyEnumerator.MoveNext())
    {
    var num = MyEnumerator.Current;

    Console.WriteLine(num);
    }
    }
    finally
    {
    MyEnumerator.Dispose();
    }
    //foreach (var num in nums)
    //{
    // Console.WriteLine(num);
    //}

    三:yield词法探索
    了解词法之前,我们需要知道的一个类:Enumerator
    这个类其实就是对list进行了一个封装,本质上所谓的movenext和current是对list进行的操作。
    yield词法生成的MSIL代码:
    .class auto ansi sealed nested private beforefieldinit '<GetNums>d__1'
    extends [mscorlib]System.Object
    implements class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>,
    [mscorlib]System.Collections.IEnumerable,
    class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>,
    [mscorlib]System.IDisposable,
    [mscorlib]System.Collections.IEnumerator

    其实 <GetNums>d__1 和 Enumerator 其实就是一样的。
    yield词法给我们生成时一个和系统定义的 Enumerator 是具有一样的功能类。

     

    4.linq基础必备之匿名方法,匿名委托,lambda前世今生 6.

     

    一:匿名方法,委托,匿名委托,lambda。。。

    1. 委托=> 函数指针

    2. 委托不是一个新概念,在其他的编程语言中早已经产生。

    javascript:非常熟悉匿名函数【闭包】

    C++: 函数指针


    3. 那么C#为了引进这个函数指针,将其进行包装成“委托”,同时将非托管的变成托管的。


    4. 委托的定义

    /// <summary>
    /// 这就是一个委托的定义
    /// </summary>
    /// <param name="str"></param>
    delegate void MyAction(string str);

    5. 委托的演化过程


    函数指针 -> 委托【高等封装】


    1. 最初的委托该怎么用???

    namespace ConsoleApplication1
    {
    class Program
    {
    static void Main(string[] args)
    {
    MyAction action = Run;

    Run("mytest");
    }

    static void Run(string str)
    {
    Console.WriteLine(str);
    }
    }

    /// <summary>
    /// 这就是一个委托的定义
    /// </summary>
    /// <param name="str"></param>
    delegate void MyAction(string str);
    }

    弊端: 写的代码量过多,在于我还必须要手写一个显示的方法(Run),那有没有好的办法让我不写显式的方法。


    2. 匿名委托

    那么匿名委托就是在Run方法上面开刀。

    namespace ConsoleApplication1
    {
    class Program
    {
    static void Main(string[] args)
    {
    MyAction action = delegate(string str)
    {
    Console.WriteLine(str);
    };
    }
    }

    /// <summary>
    /// 这就是一个委托的定义
    /// </summary>
    /// <param name="str"></param>
    delegate void MyAction(string str);
    }

    可以看到,已经成功的把显式方法去掉了,上面就是一个典型的匿名方法,其中有delegate包装了起来,

    现在可以动刀的地方就是匿名函数:
    MyAction action = delegate(string str)
    {
    Console.WriteLine(str);
    };

    有没有这种方法呢??? 有的,那就是lambda表达式。。。。


    3.lambda表达式

    MyAction action = str => Console.WriteLine(str);

    通过对比,发现原来可以向参数声明,大括号,delegate都可以踢掉。。。

    我们成功的将代码从 27 优化到了 24行。。。。


    4. 还有优化的空间吗???

    看了代码之后,惟一可以优化的地方就是delegate声明。

    因为FCL中给我们定义了三个系统委托,一个叫做Action,一个叫做Func,一个叫做Predicate。

    我们把delegate删掉之后,用了一个系统委托,成功的将代码从24号优化到了18行。

    本质上来说,我们将曾今10几行的代码 成功的优化到了1行。

    没有编译器的帮忙,绝对不能优化到这样的极致。

    5. Action 封装一个方法,该方法只有一个参数并且不返回值。

    通过ILSpy可以看到,Action最多接受8个参数。。。

    【重点在于无返回值】


    6. Func 封装一个不具有参数但却返回 TResult 参数指定的类型值的方法。

    【重点再于有返回值】

    7.Predicate 入参的类型随意,返回值必须是bool,

    从整个演化的过程来看,它就是一个代码优化,代码压缩的过程,并且非常具有优雅性。

     

  • 相关阅读:
    jvm 垃圾收集器
    MySQL 查询结果去除边框
    MySQL5.7 半同步复制技术
    MySQL 5.7半同步复制技术 zero
    redis 迁移工具 redisshake
    MySQL 如何找出占用CPU较高的SQL
    部署redis sentinel
    MySQL的SQL_CALC_FOUND_ROWS 类似count(*)
    MongoDB 副本集删除超级用户后恢复
    【Linux】关于 Systemd/Journal
  • 原文地址:https://www.cnblogs.com/dragon-L/p/6441884.html
Copyright © 2011-2022 走看看