• CSharp的lambda表达式匿名类扩展方法


    c#的lamba表达式

    之前已经写过一些关于委托还有事件的文章,今天就来介绍一下lambda表达式。
    首先定义需要的函数以及委托

    {
    public delegate void DoNothingDelegate();
    public delegate void StudyDelegate(int id, string name);
    
    private void DoNothing()
    {
        Console.WriteLine("DoNothing");
    }
    
    private void Study(int id , string name)
    {
        Console.WriteLine($"{id} {name} 学习 .Net高级班 " );
    }
    }
    

    在.net farmwork 1.0,会这样写我们的匿名函数

    
       public void Show()
       {
           {
               //.netframework 1.0的写法
               DoNothingDelegate doNothing = new DoNothingDelegate(DoNothing);
               StudyDelegate study = new StudyDelegate(Study);
           }
       }
    

    在.netframework 2.0,会这样写匿名函数, 增加了一个delegate关键字

     {
         DoNothingDelegate doNothing = new DoNothingDelegate (delegate ()
         {
             Console.WriteLine("DoNothing");
         });
         StudyDelegate study = new StudyDelegate( delegate (int id, string name)
         {
             Console.WriteLine($"{id} {name} 学习 .Net高级班 ");
         });
     }
    

    在.netframework3.0,去掉了delegate关键字了,在参数后增加了一个=> goes to

    {
        DoNothingDelegate doNothing = new DoNothingDelegate(() =>
        {
            Console.WriteLine("DoNothing");
        });
        StudyDelegate study = new StudyDelegate((int id, string name) =>
        {
            Console.WriteLine($"{id} {name} 学习 .Net高级班 ");
        });
    }
    

    在.netframework3.0后期,我们可以省略参数的信息

     StudyDelegate study = new StudyDelegate((id, name) =>
     {
         Console.WriteLine($"{id} {name} 学习 .Net高级班 ");
     });
    

    如果匿名方法体中只有一行代码,可以省略方法题的大括号

    StudyDelegate study = new StudyDelegate((id, name) =>Console.WriteLine($"{id} {name} 学习 .Net高级班 "));
    

    只有一个参数的时候,参数的小括号也可以省略掉。

    public delegate void StudyNew(int id);
    StudyNew study = id => Console.WriteLine($"{id} 学习 .Net高级班 ");
    

    如果方法返回值?
    如果lambda表达式中只有一行代码,且有返回值,可以省略return,

    Func<int> retNum= () => 1;
    

    lamba函数的本质是什么?

    这里使用ilspy进行反编译来看一下匿名方法的实现是怎么样的

    img

    本质上来说,其实就是一个方法--匿名方法, 在类里面会生成和lambad 表达式参数和返回值完全匹配的方法.

    匿名类

    有时候,可以需要创建一个临时的类对象,保存数据,方便使用。
    一个普通的类对象

    
      public class Student
      {
          public int Id { get; set; }
          public int ClassId { get; set; }
    
          public string Name { get; set; }
    
          public int Age { get; set; }
    
          public string Description { get; set; }
    
          public void Study()
          {
              Console.WriteLine($"{this.Id} {this.Name} 跟着老师学习 .Net开发");
    
          }
    
          public void StudyQt()
          {
              Console.WriteLine($"{this.Id} {this.Name} 跟着老师学习C++ Qt");
          }
      }
    
    

    当创建一个普通的类对象的时候,这样去创建一个类对象。

     Student student = new Student()
     {
         Id = 1,
         ClassId = 2,
         Name = "张三",
         Age = 20,
         Description = "这是一个学生"
     };
    

    现在尝试最原始的方法去创建一个匿名类,

    object model = new
    {
        Id = 1,
        Name = "小楼一夜听春雨",
        Age = 14,
        Description = "魔刀丁鹏"
    };
    

    为什么可以定义一个匿名的对象?

    因为C#中所有的对象都继承自Object对象.

    当尝试使用.去访问其中的属性就会报错.

    C#是强类型语言(编译时决定类型),object是在编译时确定类型,因为Object没有Id等属性,所以无法通过.去访问其中的变量.

    因此可以使用下面的方法去访问我们的匿名对象中的属性.

     dynamic model1 = new
     {
         Id = 2,
         Name = "天下第一的剑客",
         Age = 18,
         Description = "神剑山庄谢晓峰"
     };
    
     Console.WriteLine(model1.Id);
     Console.WriteLine(model1.Age);
     Console.WriteLine(model1.Amy); //报错
    

    这里使用了dynamic关键字去避开了编译器的检查,会在运行时检查,运行时决定类型.这个出现乱取的问题,导致程序崩溃.

    有什么方法可以正确的取出想访问的属性,又可以避免访问不存在的属性那?
    var关键字

      var model2 = new
      {
          Id = 3,
          Name = "天下第二的剑客",
          Age = 16,
          Description = "不会剑法的阿飞"
      };
    
      Console.WriteLine(model2.Id);
      Console.WriteLine(model2.Name);
      //Console.WriteLine(model2.Aniu); //报错!无法访问不存在的变量
    

    var类型就是弱类型的变量.

    使用的注意事项?

    1. 不能在匿名类里面声明方法,同时在声明匿名类的属性时候,就给定匿名类的属性初始值.
    2. 不能给属性重新赋值.
    3. var声明的变量必须初始化,必须能推算出类型,也不允许作为方法的参数类型.

    使用的建议?

    1. var配合匿名类型使用
    2. var偷懒,配合复杂类型时使用。
    3. 在不知道具体什么类型的时候就可以使用var来声明

    缺陷

    在代码阅读的时候,不是很方便。

    建议在大家写代码的时候,尽量明确类型。

    扩展方法

    为什么需要扩展方法?

    1. 扩展:让功能变得更加强大,让不存在功能存在. ---新增逻辑处理
    2. 已经存在方法,正常调用,扩展的东西不影响已经存在的方法
    3. 如果需求变更,需要支持另外的一个新的功能。

    接着上面学生的用例,我们可以追加一些需求.

    Student student1 = new Student()
    {
        Id = 1,
        ClassId = 2,
        Name = "张三",
        Age = 20,
        Description = "这是一个学生"
    };
    
    student1.Study();
    student1.StudyQt();
    
    

    如果要增加一个需求--学习嵌入式---直接增加方法.
    传统的方式对原有的类进行结构上的修改.

    期望:既可以增加新的功能,历史代码不变.直接增加类,在新的类中去完成.

    这里就可以使用扩展方法来完成需求.

     public static class MethodExtension
     {
         public static void StudyEmbedded(this Student student)
         {
             Console.WriteLine($"{student.Id} {student.Name} 跟着老师学习嵌入式开发");
         }
     }
    

    program.cs

    student.StudyEmbedded();
    

    可以看到做的操作就是:

    1. 把类变成静态类
    2. 把方法的第一个参数+this修饰

    这样就完成了一个扩展方法.静态方法的调用--可以像实例方法一样去调用.

    不用修改原有的任何类中的类,可以新增功能;

    有哪些场景?

    1. 有新的需求来的时候--扩展方法--保证历史代码功能
    2. 要应用第三方的DLL库(提供的功能不完善,我们自己需要升级下----dll,不能修改原有的代码)扩展方法
    3. 封装帮助类库
    4. asp.net core 中,到处都是扩展方法--框架的设计--最小化设计.提供一个最基本、最最最简单的功能,提供给调用方.这种方式在使用的时候,如果想要增强功能,就可以扩展. 好处:
      1. 尽可能简化代码
      2. 灵活分配,需要就扩展什么.按需扩展,不会有代码冗余.

    这里有个问题,我可以给任意类型写扩展方法嘛? 注意:扩展object类型.

     public static string SubObj(this object str, int len = 10)
     {
         if (str is null)
         {
             return string.Empty;
         }
    
         if (str.ToString().Length <= 10)
         {
             return str.ToString();
         }
         else
         {
             str = $"{str.ToString().Substring(0, len)}....";
             return str.ToString();
         }
    
     }
    

    program.cs

     object o = "object 类型";
     o.SubObj();
      
     int i = 1;
     i.SubObj();//可以
    
     string sr = "你好";
     sr.SubObj();
    
    
     str.SubGeneric();
     student.SubGeneric(); //隐患
    

    总结:

    1. 扩展的类型具有继承性,扩展父类,所有子类都拥有这个功能;扩展的功能可能不适用一些具体的类型;但是仍然可以调用;可以造成一些类型的功能的污染;----慎用
    2. 不建议扩展object,也不是很建议大家去泛型扩展.
  • 相关阅读:
    PHP 开发-XAMPP 安装
    基于C++的通讯发报应用课程设计
    dpkg工具、ZED相机sdk、监控nvidia
    质量小议12 -- 以测代评
    贪心算法求解活动选择问题
    东软睿驰总裁兼CTO杜强受邀出席 CICV 2024智能网联汽车技术首脑(CTO)闭门峰会
    数据结构_单链表逆置
    面试题 17.14. Smallest K LCCI
    SM4 研究与实现
    SpringBoot SpringBoot 基础篇(第一篇) 第2章 SpringBoot 全局配置 2.3 yaml 读取数据
  • 原文地址:https://www.cnblogs.com/wenlong-4613615/p/18071142