当前位置: 首页 > 编程笔记 >

C#中的扩展方法详解

南宫正阳
2023-03-14
本文向大家介绍C#中的扩展方法详解,包括了C#中的扩展方法详解的使用技巧和注意事项,需要的朋友参考一下

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

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 > 0))
    {
      return -1;
    }
 
    if (((endTime - t).TotalSeconds < 0))
    {
      return 1;
    }
 
    return 0;
  }


这里的扩展方法是用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 = "2012";
      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#中的扩展方法,包括了C#中的扩展方法的使用技巧和注意事项,需要的朋友参考一下 扩展方法是静态方法,就像它们是扩展类型的实例方法一样被调用。使用扩展方法,您可以将方法添加到现有类型中,而无需创建新的派生类型,重新编译或修改原始类型。 以下是我们创建的扩展方法。 让我们看一个使用扩展方法的例子。 示例 输出结果

  • 本文向大家介绍C#中的任何扩展方法,包括了C#中的任何扩展方法的使用技巧和注意事项,需要的朋友参考一下 该扩展方法是System.Linq的namepspace的一部分。使用此方法,可以检查是否有任何元素符合特定条件。 首先,设置一个包含元素的数组- 以下是一个示例。它检查数组中的任何元素是否大于或等于20- 这是完整的代码- 示例 输出结果

  • 本文向大家介绍.NET实用扩展方法详解,包括了.NET实用扩展方法详解的使用技巧和注意事项,需要的朋友参考一下 持续更新的.NET实用扩展方法,具体内容如下 1. 字符串转换为可空数值类型(int, long, float...类似) 2. 去除子字符串 3. 获取子序列 4. 通过指定键对序列去重, 不必实现IEqualityComparer接口 5. 获取序列中重复的元素序列, 原理和去重类似

  • 本文向大家介绍简单介绍C# 中的扩展方法,包括了简单介绍C# 中的扩展方法的使用技巧和注意事项,需要的朋友参考一下     扩展方法是C#3.0引入的新特性,使用它,可以在不修改某一类的代码的情况下,实现该类方法的扩展。     为一个类添加扩展方法,需要三个要素:         1.扩展方法所在的类为静态类         2.扩展方法本身要为静态方法         3.扩展方法的第一个参数

  • 本文向大家介绍详解PHP安装mysql.so扩展的方法,包括了详解PHP安装mysql.so扩展的方法的使用技巧和注意事项,需要的朋友参考一下 前言 因为在PHP中mysql_connect模块已经逐渐被弃用,我在搭建环境时也没有再安装mysql扩展,但是今天在维护一个老项目时,出现报错 Fatal error: Uncaught Error: Call to undefined function

  • 本文向大家介绍PHP exif扩展方法开启详解,包括了PHP exif扩展方法开启详解的使用技巧和注意事项,需要的朋友参考一下 服务器配置说明: 1.在php.ini文件中找到;extension=php_exif.dll,去掉前面的分号 2.在php.ini文件中找到;extension=php_mbstring.dll,去掉前面的分号,并将此行移动到extension=php_exif.dll