技术图文:C# 语言中的扩展方法
背景
前段时间,在知识星球立了一个Flag,在总结 Leetcode 刷题的第五篇图文时遇到了扩展方法 这个知识点,于是先总结一下。
1.扩展方法概述
扩展方法能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其它方式修改原始类型。
最常见的扩展方法是 LINQ 标准查询运算符,它将查询功能添加到现有的 System.Collection.IEnumerable
和Syste.Collection.Generic.IEnumerable<T>
类型。
若要使用标准查询运算符,要先使用 using System.Linq
指令将它们置于范围中。然后,任何实现了 IEnumerable<T>
的类型都具有 GroupBy<TSource,Tkey>
、OrderBy<TSource,TKey>
、Average
等实例方法。在 IEnumerable<T>
类型的实例(如 List<T>
或Array
)后键入“.”时,可以在 IntelliSense 语句完成中看到这些附加方法。
class Program
{static void Main(string[] args){int[] nums = new int[] { 10, 45, 15, 39, 21, 26 };List<int> result = nums.SelectMany(g =>{List<int> lst = new List<int>();if (g > 20) lst.Add(g);return lst;}).ToList();Show(result);result = nums.OrderBy(g => g).ToList();Show(result);}static void Show(List<int> lst){foreach (int i in lst){Console.Write(i + "\t");}Console.WriteLine();}
}// 45 39 21 26
// 10 15 21 26 39 45
2.扩展方法的实现与调用
扩展方法必须在非泛型静态类中定义,且该方法必须是静态(static)方法,通过实例方法语法进行调用。
第一个参数指定该方法所操作的类型,并且该参数以 this
修饰符为前缀。仅当使用 using
指令将命名空间显式导入到源代码中之后,扩展方法才位于范围中。
下面示例演示了在非嵌套的、非泛型静态类型内部,为 System.String
类定义一个扩展方法。
程序代码如下:
namespace CustomExtensions
{//定义一个静态类以包含扩展方法public static class MyExtensions{public static int WordCount(this string str){int result = str.Split(new char[] {' ', '.', '?'},StringSplitOptions.RemoveEmptyEntries).Length;return result;}}
}//在调用代码中,添加一条using指令以指定包含扩展方法类的命名空间。
using CustomExtensions;
namespace Sample
{class Program{static void Main(string[] args){string s = "The quick brown fox jumped over the lazy dog.";//按照与调用类型上的实例方法一样的方式调用扩展方法。int i = s.WordCount();Console.WriteLine("World count of s is {0}", i);}}
}
// World count of s is 9
3. 为枚举创建新方法
可以使用扩展方法对枚举类型进行扩展。
程序代码如下:
public enum Grades
{A = 4,B = 3,C = 2,D = 1,F = 0
}public static class Extensions
{public static Grades MinPassing = Grades.D;public static bool Passing(this Grades grade){return grade >= MinPassing;}
}class Program
{static void Main(string[] args){Grades g1 = Grades.D;Grades g2 = Grades.F;Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");Extensions.MinPassing = Grades.C;Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");}
}// First is a passing grade.
// Second is not a passing grade.
// First is not a passing grade.
// Second is not a passing grade.
4.在编译时绑定扩展方法的规则
可以使用扩展方法来扩展类或接口,但不能重写(override)扩展方法。与接口或类方法具有相同名称和签名的扩展方法永远不会被调用。
编译时,扩展方法的优先级总是比类型本身中定义的实例方法低。当编译器遇到方法调用时,它首先在该类型的实例方法中寻找匹配的方法。如果未找到任何匹配方法,编译器将搜索为该类型定义的任何扩展方法,并且绑定到它找到的第一个扩展方法。
程序代码如下:
namespace DefineIMyInterface
{public interface IMyInterface{void MethodB();}
}namespace Extensions
{using DefineIMyInterface;public static class Extension{public static void MethodA(this IMyInterface myInterface, int i){Console.WriteLine("Extension.MethodA(this IMyInterface myInterface, int i)");}public static void MethodA(this IMyInterface myInterface,string s){Console.WriteLine("Extension.MethodA(this IMyInterface myInterface, string s)");}public static void MethodB(this IMyInterface myInterface){Console.WriteLine("Extension.MethodB(this IMyInterface myInterface)");}}
}namespace Sample
{using DefineIMyInterface;using Extensions;class A : IMyInterface{public void MethodB(){Console.WriteLine("A.MethodB()");}}class B : IMyInterface{public void MethodB(){Console.WriteLine("B.MethodB()");}public void MethodA(int i){Console.WriteLine("B.MethodA(int i)");}}class C : IMyInterface{public void MethodB(){Console.WriteLine("C.MethodB()");}public void MethodA(object obj){Console.WriteLine("C.MethodA(object obj)");}}class Program{static void Main(string[] args){A a = new A();B b = new B();C c = new C();a.MethodA(1);a.MethodA("hello");a.MethodB();Console.WriteLine("----------");b.MethodA(1);b.MethodB();b.MethodA("hello");Console.WriteLine("----------");c.MethodA(1);c.MethodA("hello");c.MethodB();}}
}// Extension.MethodA(this IMyInterface myInterface, int i)
// Extension.MethodA(this IMyInterface myInterface, string s)
// A.MethodB()
// ----------
// B.MethodA(int i)
// B.MethodB()
// Extension.MethodA(this IMyInterface myInterface, string s)
// ----------
// C.MethodA(object obj)
// C.MethodA(object obj)
// C.MethodB()
参考文献
- https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/extension-methods
当前活动
我是 终身学习者“老马”,一个长期践行“结伴式学习”理念的 中年大叔。
我崇尚分享,渴望成长,于2010年创立了“LSGO软件技术团队”,并加入了国内著名的开源组织“Datawhale”,也是“Dre@mtech”、“智能机器人研究中心”和“大数据与哲学社会科学实验室”的一员。
愿我们一起学习,一起进步,相互陪伴,共同成长。
后台回复「搜搜搜」,随机获取电子资源!
欢迎关注,请扫描二维码:
相关文章:

如何在ToolBar中显示文字和图标,自定义图标大小,并和MenuItem关联
要注意以下几个方面,先后顺序未必正确,有可能多设几次 1.设置ToolBar可以显示文字ToolBar.ShowCaption : True;2.设置ToolButton大小ImageList.WidthImageList.Height3.设置菜单关联4.设置运行时显示图标(这个是关键)ToolButton.Menuitum.ImageIndex要保证MenuItem所在的MainMe…

C#程序调用cmd执行命令
酷小孩 原文 C#程序调用cmd执行命令 对于C#通过程序来调用cmd命令的操作,网上有很多类似的文章,但很多都不行,竟是漫天的拷贝。我自己测试整理了一下。 代码: string str Console.ReadLine();System.Diagnostics.Process p new …

Java虚拟机的内存空间有几种
Java虚拟机的内存空间有几种?(1)问题分析: JVM(虚拟机)的内存划分 不同的数据使用的是哪一块内存空间 (2)核心答案讲解: Java虚拟机有那几块内存空间: 1)栈内存:方法运行时所进入的内存,里面还会存储程序的…

技术图文:排序技术在求解算法题中的应用
背景 前段时间,在知识星球立了一个Flag,这是总结Leetcode刷题的第五篇图文。 理论部分 C# 中的排序 对集合类的排序,我们通常使用位于 System.Core 程序集,System.Linq命名空间下,Enumerable静态类中的扩展方法。 …

如果有电脑——计算机达人成长之路(36)
5、电脑情缘(一)王新华的电脑 现在的大学生一般都有一个工具,就是计算机,尤其是计算机科学系的学生,几乎人手一台。对此,木鸿飞只能深深的说上一句:“幸福啊!” 现在人可能不能了解这…

Javascript中二进制数据处理方法
Javascript中二进制数据处理方法 转载于:https://www.cnblogs.com/motadou/archive/2012/02/19/2358514.html

正规Java培训机构是什么样的
正规Java培训机构是什么样的?这对于很多想真正学习到java技术的人来说是非常重要的,选择一个适合自己的靠谱的Java培训机构,学有所成工作也是比较稳定的,下面我们来看看详细的介绍。 正规Java培训机构是什么样的?其实对于这个问题…

《40期》 我们要把世纪末日变成重生日
2012年.传说中一个会是世纪末日的一年。(ps:电影看多了……- _-!!!),但是寒假过后的北京。天气却是十分的晴朗、出奇的好。而就在今天也就是2012年2月9日40期的开班典礼就选了这一天。地点就是在育荣教学园区2栋教学楼…

LeetCode刷题宝典 V1.0 PDF下载
前段时间,在知识星球立了一个Flag,现在 Flag 的进度为 100%,很是开心。 为了大家学习的方便,所以整理了这份150多页的小册子。可以作为学习数据结构与算法或备考计算机类研究生的参考资料,希望对大家有所帮助。 小册子…

机器学习:信用风险评估评分卡建模方法及原理
#课程介绍 信用风险评分卡为信用风险管理提供了一种有效的、经验性的解决方法,是消费信贷管理中广泛应用的技术手段。 评分卡是信用风险评估领域常见的建模方法。评分卡并不加单对应于某一种机器学习算法,而是一种通用的建模框架,讲原始数据通…

0基础学怎么学习python
Python相对于其他编程语言来说是比较简单的,非常适合零基础的小白学习,想要进入到互联网行业,可以优先选择学习Python,那么下面小编就来为大家详细的介绍一下0基础学怎么学习python? 0基础学怎么学习python? 1、要读书…

nginx技术(2)nginx的配置详解
nginx的配置 1,启动nginx 1234567[rootcentos6 nginx-1.2.9]# /usr/sbin/nginx -c /etc/nginx/nginx.conf 启动nginx [rootcentos6 nginx-1.2.9]# ps -ef|grep nginx 查看进程 root 5479 1 0 04:15 ? 00:00:00 nginx: master process /usr/sbin/nginx -…

javascript 基础篇2 数据类型,语句,函数
文章里如果有错误的话,希望能帮忙指正~我也是边看视频边学习中,这个算是个笔记吧~自认为总结出来的东西比看视频要节省点时间~能帮到别人最好了~帮不到也起码恩能帮到我自己 嘿~ 写内容之前废话一句:因为旧版有些浏览器不支持javascript脚本&…

技术图文:如何在Python中定义二维数组?
背景 前几天,有位同学问我如下的问题: “temp[0][0]修改后,为什么temp[1][0]、temp[2][0]也发生了变化?” “在Python中二维数组是怎样定义和使用的?” 今天就来谈谈这个问题。 技术分析 在 C# 语言中有直接定义二…

javascript的垃圾回收机制指的是什么
定义:指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。 像 C 这样的编程语言,具有低级内存管理原语,如 malloc()和 free()。开发人员使用这些原语显式地对操作系统的内存进行分配和释放。 而 JavaScript…

技术图文:Matlab向量 VS. Python列表
背景 前段时间在知识星球上立了一个Flag,至少写10篇关于 Python,Matlab 和 C# 对比的总结。这是第 1 篇,从创建结构、添加元素、删除元素、获取元素四个角度来对比 Matlab 的向量与 Python 的列表。 1. 向量/列表 的创建 1.1 直接法 Matla…

我的ExtJS学习之路 ——4
项目基本架子出来,然后就该考虑将封装好的gridpanel 和 tabpanel关联起来 既 点击树的叶子节点,将 gridpanel 展现在 tabpanel中 怎么关联呢? 【在之前的基础上的,重复的代码就不贴出来了】 我改变了 模拟数据的形式,注…

php CI框架输出空行问题排查
今天在使用 curl 命令行工具调试一个功能时,发现输出的内容总是会在最开始莫名其妙的多一行空行: 项目框架是 php 的 CodeIgniter,感觉这种问题在网上不好查找,因为可以确定这个是业务出现的问题,然后只能自己去定位查…

哪些人适合学习软件测试
软件测试相对于其他编程语言来说,它的入门门槛是相对比较低的,想要从事IT互联网行业可以选择学习软件测试,那么都有哪些人适合学习软件测试呢?来看看下面的详细介绍吧。 哪些人适合学习软件测试?就在软件测试培训行业观察来看,小…

c语言基本函数
一.内存操作函数: (1) 头文件:#include <string.h>memset() 函数用来将指定内存的前n个字节设置为特定的值,其原型为: void * memset( void * ptr, int value, size_t num );参数说明:…

技术图文:Python 匿名函数 VS. C# Lambda表达式
背景 前段时间在知识星球上立了一个Flag,至少写10篇关于 Python,Matlab 和 C# 对比的总结。 这是第 2 篇,从定义和应用两个角度来对比 Python 的匿名函数 与 C# 的Lambda表达式。 匿名函数/Lambda表达式的定义 Python 匿名函数 在 Python…

php是否区分大小写
按常理来说,大多数语言都是区分大小写的,比如变量 ab 和 AB 是不同的,函数cd 和 CD 也是不同的,但是php有点特别。 首先,php中的变量和常量是区分大小写的。 <?php$a a; $A A; echo $a; echo $A;?>这里打印了…

如何创建和获取正则对象?
在JavaSript应用中,使用正则表达式之前,需要创建正则对象。创建正则表达式的方式有两种,一种是用字面量方式创建,另种是通过RegExp0构造函数的方式创建。这两种方式的语法格式如下。 //字面量方式 var变量名/表达式/; // RegExp构…

Numpy入门教程:01. 数组的创建与属性
背景 什么是 NumPy 呢? NumPy 这个词来源于两个单词 – Numerical和Python。其是一个功能强大的 Python 库,可以帮助程序员轻松地进行数值计算,通常应用于以下场景: 执行各种数学任务,如:数值积分、微分、…

深入浅出WPF——x:Class详解
小序:按照惯例,我会在年末的最后一篇文章里感谢所有帮助过我的人们。今年也不例外,只是形式简单一些。祝所有帮助过我的朋友、同事、学生和兄弟姐妹们——2009年身体健康、平安快乐、财源滚滚。愿2009年的中国,平安祥和、远离各种…

SQL Date 函数
MySQL Date 函数 函数描述NOW()返回当前的日期和时间CURDATE()返回当前的日期CURTIME()返回当前的时间DATE()提取日期或日期/时间表达式的日期部分EXTRACT()返回日期/时间按的单独部分DATE_ADD()给日期添加指定的时间间隔DATE_SUB()从日期减去指定的时间间隔DATEDIFF()返回两个…

什么是java常量
相信很多在学java技术的同学,对java常量这个并不陌生,什么是java常量呢?java常量就是在程序中固定不变的值,是不能改变的数据。例如数字1、字符“a”、浮点数3.2等。在Java中,常量包括整型常量、浮点数常量、布尔常量、字符常量等…

Numpy入门教程:02. 索引、切片与迭代
背景 什么是 NumPy 呢? NumPy 这个词来源于两个单词 – Numerical和Python。其是一个功能强大的 Python 库,可以帮助程序员轻松地进行数值计算,通常应用于以下场景: 执行各种数学任务,如:数值积分、微分、…

php中OR与|| AND与的区别
本身没有区别,习惯问题 ,但是有时候牵涉到运算符优先级的问题,结果会不同,记录下。例如:$p 6 or 0;var_dump($p);//int(6)$p 6 || 0;var_dump($p);//bool(true)$p 6 and 0;var_dump($p); //int(6) $p 6 &&…

beego数据输出
概览直接输出字符串模板数据输出 静态模板数据输出动态模板数据输出json格式数据输出xml格式数据输出jsonp调用概览 直接输出字符串 通过beego.Controller.Ctx.WriteString()方法可以直接向http response body中输出字符串 beego中的函数定义如下: // WriteString W…