背景

前段时间,在知识星球立了一个Flag,在总结 Leetcode 刷题的第五篇图文时遇到了扩展方法 这个知识点,于是先总结一下。

1.扩展方法概述

扩展方法能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其它方式修改原始类型。

最常见的扩展方法是 LINQ 标准查询运算符,它将查询功能添加到现有的 System.Collection.IEnumerableSyste.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”、“智能机器人研究中心”和“大数据与哲学社会科学实验室”的一员。

愿我们一起学习,一起进步,相互陪伴,共同成长。

后台回复「搜搜搜」,随机获取电子资源!
欢迎关注,请扫描二维码:

技术图文:C# 语言中的扩展方法相关推荐

  1. C#中的扩展方法学习总结

      版权声明:本文由秦元培创作和发表,采用署名(BY)-非商业性使用(NC)-相同方式共享(SA)国际许可协议进行许可,转载请注明作者及出处,本文作者为秦元培,本文标题为C#中的扩展方法学习总结,本文 ...

  2. c语言中怎么排序,c语言中的排序方法.doc

    c语言中的排序方法 排序技术 所谓排序,就是要整理的文件中的记录,使之按关键字第增(或第减)的次序排列起来. 常用交换类排序 冒泡排序法是一种最简单的交换类排序方法,它是通过相邻数据元素的交换逐步将线 ...

  3. C语言中常用计时方法总结

    转自:http://blog.csdn.net/fz_ywj/article/details/8109368 C语言中常用计时方法总结 1. time() 头文件:time.h 函数原型:time_t ...

  4. python字符串截取方法_如何使用python语言中的字符串方法截取字符串

    在我们使用python语言中的字符串方法时,可能会判断某个字符串是否以什么开头,可以使用什么进行截取等.下面利用几个实例说明字符串中的方法的用法,操作如下: 工具/原料 python 截图工具 方法/ ...

  5. Python语言中的注释方法应用

    Python语言中的注释方法 在Python编程中,与其他编程语言一样,有良好的注释部分,会让你的程序在后续的改进或优化中,变得便利.同时,给自己培养了良好的编程习惯. 在Python语言中,有两种注 ...

  6. c语言计时纳秒_C语言中常用计时方法总结

    转自:http://blog.csdn.net/fz_ywj/article/details/8109368 C语言中常用计时方法总结 1. time() 头文件:time.h 函数原型:time_t ...

  7. C#中的扩展方法,Linq,IO和多线程的定义和实例

    前段时间学C#的上转型,泛型,lambda表达式这些应用的理解很费劲.学过之后我多多的练习了几天,接下来继续复习C#的其他一些概念,说实在的这些知识点学过之后很容易忘,但是都是很重要的,所以发表在博客 ...

  8. .Net 2.0中使用扩展方法

    大家都知道扩展方法是不能直接在2.0中使用的 需要引用一个‍System.Core的dll 不过现在有更加简单的方法了 只要在工程项目中加入以下代码就OK啦 ‍namespace System.Run ...

  9. 在.net 2.0/3.0程序中使用扩展方法

    .NET Framework 从2.0升级至3.0/3.5中,增加了不少编译器级别的语法糖,如var关键字.自动属性.Lambda表达式.扩展方法等等. 如果使用vs2008发布.net2.0程序时, ...

最新文章

  1. Java基础——组合关系
  2. mysql忘记数据库密码
  3. 如何使用mysql索引查询_MYSQL索引问题:索引在查询中如何使用?
  4. ubuntu 21.04创建桌面快捷方式的方法
  5. Error creating bean with name ‘org.springframework.security.oauth2.config.annotation.web.configurati
  6. Dubbo详解-说明(一)
  7. 手机号段对应地区编码_漫画:“哈夫曼编码” 是什么鬼?
  8. oracle 数据库字段名与实体类字段名称不匹配的处理方法
  9. 在崩溃或断电后测试Lucene的索引耐久性
  10. [译]不要在UI主线程中进行耗时的操作
  11. 数值计算方法(高斯消元以及LU分解)
  12. 淘宝双12惊喜——“寻”千兆,万兆光模块等你来
  13. CCF NOI1045 元素之和
  14. 深度学习笔记 | 第16讲:语音识别——一份简短的技术综述
  15. ERROR: The environment variable VG_GNU_PACKAGE must be set. Aborting.
  16. zxing绘制条形码总结
  17. oracle导数时不包含某个表,EXPDP导数报ORA-00942案例
  18. aws beanstalk mysql_AWS CloudFormation与BeanStalk的联系与区别
  19. 2019小程序创业如何把握正确方向
  20. 清北学堂 2017-10-01

热门文章

  1. git克隆 不带目录_Git 系统学习笔记
  2. java泛型的实现和原理_java 泛型实现原理
  3. android native java_在Android Native层中创建Java虚拟机实例
  4. JavaScript 慢慢移动的海绵宝宝
  5. JAX-RS(基于Jersey) + Spring 4.x + MyBatis构建REST服务架构
  6. mkdir、rmdir命令、head、tail命令
  7. 专有云到混合云,是云计算的下半场?
  8. 如何在JSP页面中获取当前系统时间转
  9. HQL中的Like查询需要注意的地方
  10. Luna的大学读书史(1,Intro)