“扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。”这是msdn上说的,也就是你可以对String,Int,DataRow,DataTable等这些类型的基础上增加一个或多个方法,使用时不需要去修改或编译类型本身的代码。

扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用。 以上是msdn官网对扩展方法的描述,现在我通过一个情景例子来对此进行阐释。假设一个控制台程序class Program{}里面的主函数如下:

static void Main(string[] args)
{
DateTime now = DateTime.Now;
string time = now.ToString("yyyy-mm-dd hh:mm:ss");
Console.WriteLine(time);
Console.ReadKey();
}

假设需求变了,日期的显示格式要变成"yyyy-mm-dd"这种格式,当然只需要初始化time时按下面写法改写即可:

string time = now.ToString("yyyy-mm-dd");
但是如果要改变日期格式的有很多个类呢?每个都要改一次吗?这样一旦需求变来变去就忙死人了。传统的解决方式是封装一个帮助类,在里面写方法,然后供其他类调用。

本例在当前项目模仿添加一个DateHelper类:public class DateHelper{},在类里面定义方法:

public static string DateToString(DateTime dt)
{
return dt.ToString("yyyy-mm-dd hh:mm:ss");
}

于是原来的主函数改写如下:

static void Main(string[] args)
{
DateTime now = DateTime.Now;
string time = DateHelper.DateToString(now);
Console.WriteLine(time);
Console.ReadKey();
}

此时如果变需求,只需要改写DateHelp类里的DateToString()方法就行了,不管有多少个类调用此方法,都会被影响。问题解决了,可是这样要调用另一个类的方法,还是有点麻烦,有没有什么方法能够让我们像now.DateToString()一样直接调用呢?当然DateTime是微软写好的,我们改不了,无法创建想要的实例方法,于是,便引出了扩展方法。
下面是扩展方法的要素:

1.此方法必须是一个静态方法

2.此方法必须放在静态类中

3.此方法的第一个参数必须以this开头,并且指定此方法是扩展自哪个类型

根据以上要素,我们DateHelper类改成静态类:public static class DateHelper{} ,同时改写DateToString()方法:

public static string DateToString(this DateTime dt)
{
return dt.ToString("yyyy-mm-dd hh:mm:ss");
}

此时回到主函数方法体,输入"now."便可以看见自动提示有个DateToString()方法,于是代码可以这样写:

static void Main(string[] args)
    {
      DateTime now = DateTime.Now;
      string time = now.DateToString();
      Console.WriteLine(time);
      Console.ReadKey();
    }

显而易见,这样用起来会更加便捷,而且这样让我们看起来确实就像是被扩展类型本身具有的实例方法一样,可读性很高。下面概括一下扩展方法的特点:

1.扩展方法扩展自哪个类型,就必须是此类型的变量来使用,其他类型无法使用,本例扩展自DateTime类型,就只能是被DateTime类型的变量.出来(now.DateToString())
2.扩展方法中的this后面的参数不属于方法的参数,本例是无参数,this后面的DateTime dt是指明扩展方法扩展自何种类型
3.如果扩展方法和实例方法具有相同的签名,则优先调用实例方法
4.扩展自父类上的方法,可以被子类的对象直接使用
5.扩展自接口上的方法,可以被实现类的对象直接使用
6.扩展方法最终还是被编译器编译成:静态类.静态方法(),本例中now.DateToString()最终还是会被编译成DateHelper.DateToString(now),这是它的本质

实际上,我们可能会遇到这样的情景,如在接口扩展一个方法的时候,所有的原本已实现该接口的类都要实现新扩展的方法,这样的改动是一个很麻烦的工作,可以使用扩展方法“曲线救国”;而有时候我们想为某个类添加新方法却不想改动这个类,那么扩展方法这种“伪添加”方法的方式就体现出它的价值了。最常见的扩展方法是LINQ标准查询运算符,运用广泛,这种方便快捷的方式理应博得码农们点1024个赞。

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

这是msdn上说的,也就是你可以对String,Int,DataRow,DataTable等这些类型的基础上增加一个或多个方法,使用时不需要去修改或编译类型本身的代码。

先做个例子吧,以String为例,需要在字符串类型中加一个从字符串转为数值的功能。

以往我们可能是这样做的,会专门写一个方法做过转换

public static int StrToInt(string s)
{
  int id;
  int.TryParse(s, out id);//这里当转换失败时返回的id为0
  return id;
}

调用就使用

string s = "abc";
int i = StrToInt(s);

若是String类型有一个名为ToInt()(从字符串转为数值)的方法,就可以这样调用了

string s = "abc";
int i = s.ToInt();

这样看起来是不是更好,下面来看看具体怎么实现吧

第一步:

我先创建一个解决方案,一个web应用程序(webtest)及一个类库(W.Common)

在webtest项目添加引用W.Common项目

第二步:在类库中新建一个名为EString.cs类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
  
namespace W.Common
{
  public static class EString
  {
    /// <summary>
    /// 将字符串转换为Int
    /// </summary>
    /// <param name="t"></param>
    /// <returns>当转换失败时返回0</returns>
    public static int ToInt(this string t)
    {
      int id;
      int.TryParse(t, out id);//这里当转换失败时返回的id为0
      return id;
    }
  }
}

看了上面的代码了吧,扩展方法规定类必须是一个静态类,EString是一个静态类,里面包含的所有方法都必须是静态方法。

msdn是这样规定扩展方法的:“扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。 它们的第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀。”

EString里有一个ToInt的静态方法,他接收一个自身参数this,类型为string,this string必须在方法参数的第一个位置。

这句话什么意思,即你需要对string扩展一个ToInt方法,this是string实例化后的对象,这可能说的不太清楚,我的表述能力能弱,不要见怪呀。。。通俗的说就是,扩展方法跟静态类的名称无关,只需要在一个静态类里面定义一个静态方法,第一个参数必须this string开头。

如果需要你要对DateTime类型扩展方法名为IsRange(判断是否在此时间范围内),代码如下:

/// <summary>
  /// 此时间是否在此范围内 -1:小于开始时间 0:在开始与结束时间范围内 1:已超出结束时间
  /// </summary>
  /// <param name="t"></param>
  /// <param name="startTime"></param>
  /// <param name="endTime"></param>
  /// <returns></returns>
  public static int IsRange(this DateTime t, DateTime startTime, DateTime endTime)
  {
    if (((startTime - t).TotalSeconds > ))
    {
      return -;
    }
  
    if (((endTime - t).TotalSeconds < ))
    {
      return ;
    }
  
    return ;
  }

这里的扩展方法是用this DateTime打头,那么就可以这样调用

time.IsRange(t1,t2);//判断时间time是否在t1到t2的范围内
当前代码在使用扩展方法前需要先引用命名空间

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using W.Common;//这里引用扩展方法所在的命名空间
  
namespace webtest
{
  public partial class _Default : System.Web.UI.Page
  {
    protected void Page_Load(object sender, EventArgs e)
    {
      use1();
      Response.Write("<br />");
      use2();
    }
  
    /// <summary>
    /// 没有用扩展方法
    /// </summary>
    private void use1()
    {
      string s = "abc";
      int i = StrToInt(s);
      Response.Write("没有用扩展方法:" + i);
    }
  
    /// <summary>
    /// 使用扩展方法
    /// </summary>
    private void use2()
    {
      string s = "";
      int i = s.ToInt();
      Response.Write("使用扩展方法:" + i);
    }
  
    public static int StrToInt(string s)
    {
      int id;
      int.TryParse(s, out id);//这里当转换失败时返回的id为0
      return id;
    }
  }
}

以上是我对扩展方法理解及使用,如有不对或不足的地方请多多指正,谢谢啦。。

这我第一次写文章算是排过版的,用好长时间呀,以前都只是看别人的文章,现在才知道写一篇好的文章真的不容易呀。

努力学习,坚持自己的梦想。

C#中的扩展方法详解的更多相关文章

  1. 开启PHP exif扩展方法详解

    服务器配置说明: 1.在php.ini文件中找到;extension=php_exif.dll,去掉前面的分号2.在php.ini文件中找到;extension=php_mbstring.dll,去掉 ...

  2. Java中的main()方法详解

    在Java中,main()方法是Java应用程序的入口方法,也就是说,程序在运行的时候,第一个执行的方法就是main()方法,这个方法和其他的方法有很大的不同,比如方法的名字必须是main,方法必须是 ...

  3. Python 在子类中调用父类方法详解(单继承、多层继承、多重继承)

    Python 在子类中调用父类方法详解(单继承.多层继承.多重继承)   by:授客 QQ:1033553122   测试环境: win7 64位 Python版本:Python 3.3.5 代码实践 ...

  4. Python中格式化format()方法详解

    Python中格式化format()方法详解 Python中格式化输出字符串使用format()函数, 字符串即类, 可以使用方法; Python是完全面向对象的语言, 任何东西都是对象; 字符串的参 ...

  5. (转)shell中test命令方法详解

    test命令用法.功能:检查文件和比较值 shell中test命令方法详解 原文:https://www.cnblogs.com/guanyf/p/7553940.html 1)判断表达式 if te ...

  6. 关于 redux-saga 中 take 使用方法详解

    本文介绍了关于redux-saga中take使用方法详解,分享给大家,具体如下: 带来一个自己研究好久的API使用方法. redux-saga中effect中take这个API使用方式,用的多的是ca ...

  7. JavaScript中数组Array方法详解

    ECMAScript 3在Array.prototype中定义了一些很有用的操作数组的函数,这意味着这些函数作为任何数组的方法都是可用的. 1.Array.join()方法 Array.join()方 ...

  8. Laravel框架中的make方法详解

    为什么网上已经有这么多的介绍Laravel的执行流程了,Laravel的容器详解了,Laravel的特性了,Laravel的启动过程了之类的文章,我还要来再分享呢? 因为,每个人的思维方式和方向是不一 ...

  9. jquery中的ajax方法详解

    定义和用法ajax() 方法通过 HTTP 请求加载远程数据.该方法是 jQuery 底层 AJAX 实现.简单易用的高层实现见 $.get, $.post 等.$.ajax() 返回其创建的 XML ...

随机推荐

  1. 浏览器兼容之条件注释,cssHack

    对于形形色色的浏览器,随之而来的就是一些兼容问题,大多应该都是IE下的兼容问题,因为任何浏览器下出现渲染不一致都极有可能是我们自己的结构或样式不符合W3C的某些要求,或者说违背了浏览器的某些规则而先造 ...

  2. 文末两大福利 | 微软Inspire大会全接触:微软发布Microsoft 365......

    在7月11日举行的“Inspire年度合作伙伴大会”上 ,微软首席执行官萨提亚·纳德拉发布了Microsoft 365. 它包含了:Office 365.Windows 10和企业移动性+安全性(En ...

  3. HDFS读写策略

    数据的读取过程: 数据读取: 客户端调用FileSystem 实例的open 方法,获得这个文件对应的输入流InputStream. 通过RPC 远程调用NameNode ,获得NameNode 中此 ...

  4. HDU 5452 Minimum Cut (Spaning Tree)

    生成树的上的一个非根结点对应一条生成树上的边,然后这个结点的子树上连出去的边就对应去掉这条边的割, 然后就可以对树外的边求LCA,在LCA上标记,利用这个信息可以算出有多少条边在子树上,以及有多少条边 ...

  5. UVA225 Golygons 黄金图形(dfs+回溯)

    剪枝1:在同一个维度上的点具有相同的奇偶性,如果奇数数量只有奇数个那么一定不能返回原点. 剪枝2:当前位置怎么也走不回去. 3:沿途判断障碍即可. 在oj上提交0.347s,最快的0.012s,应该有 ...

  6. mac安装webpack失败

    最近开始接触构建工具webpack,公司电脑是 windows,而我自己的呢是mac.本来以为在自己电脑安装很简单,但是出了点问题,所以写出来分享下. 这里用npm的方式安装,首先你要安装node.j ...

  7. webpack安装包的时候 1程序目录不要在C盘 2路径不要有中文 3用cnpm

    webpack安装包的时候 1程序目录不要在C盘 2路径不要有中文 3用cnpm

  8. Problem T: 结构体--学生信息排序

    Problem T: 结构体--学生信息排序 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 2219  Solved: 1305[Submit][Sta ...

  9. python_106_创建类的两种方式

    class Foo(object): def __init__(self, name): self.name = name f = Foo("alex") print(type(f ...

  10. VC-基础:vs2010快捷键

    F12: 转到所调用过程或变量的定义 CTRL + SHIFT + B生成解决方案 CTRL + F7 生成编译 CTRL + O 打开文件 CTRL + SHIFT + O打开项目 CTRL + S ...