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

2024-03-19 20:20

本文主要是介绍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,也不是很建议大家去泛型扩展.

这篇关于CSharp的lambda表达式匿名类扩展方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/827130

相关文章

Python字符串处理方法超全攻略

《Python字符串处理方法超全攻略》字符串可以看作多个字符的按照先后顺序组合,相当于就是序列结构,意味着可以对它进行遍历、切片,:本文主要介绍Python字符串处理方法的相关资料,文中通过代码介... 目录一、基础知识:字符串的“不可变”特性与创建方式二、常用操作:80%场景的“万能工具箱”三、格式化方法

springboot+redis实现订单过期(超时取消)功能的方法详解

《springboot+redis实现订单过期(超时取消)功能的方法详解》在SpringBoot中使用Redis实现订单过期(超时取消)功能,有多种成熟方案,本文为大家整理了几个详细方法,文中的示例代... 目录一、Redis键过期回调方案(推荐)1. 配置Redis监听器2. 监听键过期事件3. Redi

基于SpringBoot实现分布式锁的三种方法

《基于SpringBoot实现分布式锁的三种方法》这篇文章主要为大家详细介绍了基于SpringBoot实现分布式锁的三种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、基于Redis原生命令实现分布式锁1. 基础版Redis分布式锁2. 可重入锁实现二、使用Redisso

自定义注解SpringBoot防重复提交AOP方法详解

《自定义注解SpringBoot防重复提交AOP方法详解》该文章描述了一个防止重复提交的流程,通过HttpServletRequest对象获取请求信息,生成唯一标识,使用Redis分布式锁判断请求是否... 目录防重复提交流程引入依赖properties配置自定义注解切面Redis工具类controller

Java调用DeepSeek API的8个高频坑与解决方法

《Java调用DeepSeekAPI的8个高频坑与解决方法》现在大模型开发特别火,DeepSeek因为中文理解好、反应快、还便宜,不少Java开发者都用它,本文整理了最常踩的8个坑,希望对... 目录引言一、坑 1:Token 过期未处理,鉴权异常引发服务中断问题本质典型错误代码解决方案:实现 Token

Nginx 访问控制的多种方法

《Nginx访问控制的多种方法》本文系统介绍了Nginx实现Web访问控制的多种方法,包括IP黑白名单、路径/方法/参数控制、HTTP基本认证、防盗链机制、客户端证书校验、限速限流、地理位置控制等基... 目录一、IP 白名单与黑名单1. 允许/拒绝指定IP2. 全局黑名单二、基于路径、方法、参数的访问控制

Python中Request的安装以及简单的使用方法图文教程

《Python中Request的安装以及简单的使用方法图文教程》python里的request库经常被用于进行网络爬虫,想要学习网络爬虫的同学必须得安装request这个第三方库,:本文主要介绍P... 目录1.Requests 安装cmd 窗口安装为pycharm安装在pycharm设置中为项目安装req

nginx跨域访问配置的几种方法实现

《nginx跨域访问配置的几种方法实现》本文详细介绍了Nginx跨域配置方法,包括基本配置、只允许指定域名、携带Cookie的跨域、动态设置允许的Origin、支持不同路径的跨域控制、静态资源跨域以及... 目录一、基本跨域配置二、只允许指定域名跨域三、完整示例四、配置后重载 nginx五、注意事项六、支持

MySQL查看表的历史SQL的几种实现方法

《MySQL查看表的历史SQL的几种实现方法》:本文主要介绍多种查看MySQL表历史SQL的方法,包括通用查询日志、慢查询日志、performance_schema、binlog、第三方工具等,并... 目录mysql 查看某张表的历史SQL1.查看MySQL通用查询日志(需提前开启)2.查看慢查询日志3.

MySQL底层文件的查看和修改方法

《MySQL底层文件的查看和修改方法》MySQL底层文件分为文本类(可安全查看/修改)和二进制类(禁止手动操作),以下按「查看方法、修改方法、风险管控三部分详细说明,所有操作均以Linux环境为例,需... 目录引言一、mysql 底层文件的查看方法1. 先定位核心文件路径(基础前提)2. 文本类文件(可直