扩展方法能够向现有类型“添加”方法,而无需创建新的派生类型,重新编译或以其他方式修改原始类型。扩展方法必须是静态方法,可以像实例方法一样进行调用。且调用同名中实际定义的方法优先级要高于扩展方法。

先来看看在经常使用List类型中使用扩展方法的例子,首先看看List是如何定义的:

  1. // 摘要:
  2. // Represents a strongly typed list of objects that can be accessed by index.
  3. // Provides methods to search, sort, and manipulate lists.To browse the .NET
  4. // Framework source code for this type, see the Reference Source.
  5. //
  6. // 类型参数:
  7. // T:
  8. // The type of elements in the list.
  9. [Serializable]
  10. [DebuggerDisplay("Count = {Count}")]
  11. [DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))]
  12. public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
  13. {
  14. // 摘要:
  15. // Initializes a new instance of the System.Collections.Generic.List<T> class
  16. // that is empty and has the default initial capacity.
  17. [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
  18. public List();
  19. //
  20. // 摘要:
  21. // Initializes a new instance of the System.Collections.Generic.List<T> class
  22. // that contains elements copied from the specified collection and has sufficient
  23. // capacity to accommodate the number of elements copied.
  24. //
  25. // 参数:
  26. // collection:
  27. // The collection whose elements are copied to the new list.
  28. //
  29. // 异常:
  30. // System.ArgumentNullException:
  31. // collection is null.
  32. public List(IEnumerable<T> collection);
  33. ……
  34. }

在List的类型定义中我们并没有看到有定义Union方法的地方,但是当我们在调用的时候就会出现:

  1. <span style="white-space:pre"> </span>/// <summary>
  2. /// 通过集合使用
  3. /// </summary>
  4. /// <param name="needSearchList"></param>
  5. /// <param name="areaid"></param>
  6. /// <returns></returns>
  7. public List<AreaLineInfoModel> UseSetSearchCollection(List<AreaLineInfoModel> needSearchList, int areaid)
  8. {
  9. if (needSearchList == null || !needSearchList.Any()) return null;
  10. const int area15 = 15;
  11. var area15List = new List<AreaLineInfoModel>();
  12. const int area16 = 16;
  13. var area16List = new List<AreaLineInfoModel>();
  14. const int area17 = 17;
  15. var area17List = new List<AreaLineInfoModel>();
  16. needSearchList.ForEach(
  17. m =>
  18. {
  19. if (m.AreaIdList.Contains(area15)) area15List.Add(m);
  20. if (m.AreaIdList.Contains(area16)) area16List.Add(m);
  21. if (m.AreaIdList.Contains(area17)) area17List.Add(m);
  22. });
  23. if (areaid == area15) return area15List.Union(area16List).Union(area17List).ToList();
  24. if (areaid == area16) return area16List.Union(area15List).Union(area17List).ToList();
  25. if (areaid == area17) return area17List.Union(area15List).Union(area16List).ToList();
  26. return null;
  27. }

其中的Union方法哪里来的呢?我们转到定义看一看:

  1. namespace System.Linq
  2. {
  3. public static class Enumerable
  4. {
  5. ……
  6. public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) {
  7. if (first == null) throw Error.ArgumentNull("first");
  8. if (second == null) throw Error.ArgumentNull("second");
  9. return UnionIterator<TSource>(first, second, null);
  10. }
  11. }
  12. }

so,也就是说,List的一个实例里面可以调用Enumerable里面的Union方法,如果我们不知道有扩展方法这回事的时候,以通常的想法,通过继承关系来找Union方法,会发现,List并没有实现Union方法,而且在继承的接口中也没有定义Union方法。这就比较纳闷了,这不是违背了面向对象的三大基本原则么?此话后说,我们先来自己实现一个扩展方法:

  1. public interface IFreshList<T>
  2. {
  3. }
  4. public static class testjinni
  5. {
  6. public static IFreshList<TSource> Union<TSource>(this IFreshList<TSource> first, IFreshList<TSource> second)
  7. {
  8. return second;
  9. }
  10. }
  11. public class MyList<T> : IFreshList<T>
  12. {
  13. }
  14. public class use
  15. {
  16. public void meth()
  17. {
  18. var temiList=new MyList<int>();
  19. var mdaidnnf = new MyList<int>();
  20. temiList.Union(mdaidnnf);
  21. }
  22. }

这只是一个简单的例子,你可以做你自己的扩展方法。

所有对象都能使用扩展:

public static class ExtendExt
{
  public static void FuncExt(this object obj)
  {
    int b = 0;
  }
}

msdn是这样规定扩展方法的:“扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。 它们的第一个参数指定该方法作用于哪个

类型,并且该参数以 this 修饰符为前缀。”通俗的说就是,扩展方法跟静态类的名称无关,只需要在一个静态类里面定义一个静态方法,第一个参数必须this T开头,

这个T就是一个泛型类型了。

小结:

本质上来说: 扩展方法是破坏原来的层次结构,通过网络结构加快业务逻辑处理;

扩展方法不改变被扩展类的代码,不用重新编译、修改、派生被扩展类;

扩展方法不能访问被扩展类的私有成员;

扩展方法会被被扩展类的同名方法覆盖,所以实现扩展方法我们需要承担随时被覆盖的风险;

扩展方法看似实现了面向对象中扩展对修改说不的特性,但是也违背了面向对象的继承原则,被扩展类的派生类是不能继承扩展扩展方法的,从而又违背了面向对象的多态性。;

在我们稳定的引用同一个版本的类库,但是我们没有该类库的源代码,那么我们可以使用扩展方法;但是从项目的可扩展、可维护和版本控制方面来说,都不建议使用扩展方法进行类的扩展。

文章转载自:https://blog.csdn.net/qin_zhangyongheng/article/details/52469476

(转)c# 扩展方法的更多相关文章

  1. .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法

    .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法 0x00 为什么需要Map(MapWhen)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...

  2. .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类

    .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类 0x00 为什么要引入扩展方法 有的中间件功能比较简单,有的则比较复杂,并且依赖其它组件.除 ...

  3. 为IEnumerable<T>添加RemoveAll<IEnumerable<T>>扩展方法--高性能篇

    最近写代码,遇到一个问题,微软基于List<T>自带的方法是public bool Remove(T item);,可是有时候我们可能会用到诸如RemoveAll<IEnumerab ...

  4. C#的扩展方法解析

    在使用面向对象的语言进行项目开发的过程中,较多的会使用到“继承”的特性,但是并非所有的场景都适合使用“继承”特性,在设计模式的一些基本原则中也有较多的提到. 继承的有关特性的使用所带来的问题:对象的继 ...

  5. 扩展方法(C#)

    扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型.扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用. 下面的示例为String添加 ...

  6. 扩展方法解决LinqToSql Contains超过2100行报错问题

    1.扩展方法 using System; using System.Collections.Generic; using System.Linq; using System.Web; using Sy ...

  7. C#扩展方法

    扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法就相当于一个马甲,给一个现有类套上,就可以为这个类添加其他方法了. 马甲必须定义为stati ...

  8. 枚举扩展方法获取枚举Description

    枚举扩展方法 /// <summary> /// 扩展方法,获得枚举的Description /// </summary> /// <param name="v ...

  9. 扩展方法 1 简单的string扩展方法

    这里是关于 String的简单扩展方法 (静态类 静态方法 this 类型 这里是string) static class Program { static void Main(string[] ar ...

  10. C#中的扩展方法

    扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用. 以上是msdn官网对扩展方 ...

随机推荐

  1. 一次 Java 内存泄漏排查过程,涨姿势

    人人都会犯错,但一些错误是如此的荒谬,我想不通怎么会有人犯这种错误.更没想到的是,这种事竟发生在了我们身上.当然,这种东西只有事后才能发现真相.接下来,我将讲述一系列最近在我们一个应用上犯过的这种错误 ...

  2. 11: python中的轻量级定时任务调度库:schedule

    1.1 schedule 基本使用 1.schedule 介绍 1. 提到定时任务调度的时候,相信很多人会想到芹菜celery,要么就写个脚本塞到crontab中. 2. 不过,一个小的定时脚本,要用 ...

  3. opencv学习之路(9)、对比度亮度调整与通道分离

    一.对比度亮度调整 #include<opencv2/opencv.hpp> using namespace cv; #define WIN_NAME "输出图像" M ...

  4. debian下如何源码安装tmux

    一.源码安装ncurses库 1.1 获取源码 wget https://invisible-island.net/datafiles/release/ncurses.tar.gz tar xvf n ...

  5. centos 编译lantrn

    github上的安装指导: Custom fork of Go is currently required. We'll eventually switch to Go 1.7 which suppo ...

  6. 马虎的算式|2013年蓝桥杯B组题解析第二题-fishers

    小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了. 有一次,老师出的题目是:36 x 495 = ? 他却给抄成了:396 x 45 = ? 但结果却很戏剧性,他的答案竟然是对的!! 假设 ...

  7. java 之 xml 之解析工具jaxp

    一.jaxp的api查看 *jaxp是javase一部分 *jaxp解析器在jdk的javax.xml.parsers包里面 *共四个类:分别针对dom和sax解析使用的类 *dom解析类: Docu ...

  8. MySQL 安装步骤

    今天用了一下MySQL,刚好看到之前电保存脑的笔记,于是整理了一下,还是记在博客上方便查询. 1.官网下载https://dev.mysql.com/downloads/mysql/之前安装的是mys ...

  9. P4721【模板】分治 FFT

    瞎扯 虽然说是FFT但是还是写了一发NTT(笑) 然后忘了IDFT之后要除个n懵逼了好久 以及递归的时候忘了边界无限RE 思路 朴素算法 分治FFT 考虑到题目要求求这样的一个式子 \[ F_x=\S ...

  10. P2633 Count on a tree

    思路 运用树上差分的思想,转化成一个普通的主席树模型即可求解 代码 #include <cstdio> #include <algorithm> #include <cs ...