C#中的扩展方法及用途

GPS平台、网站建设、软件开发、系统运维,找森大网络科技!
http://cnsendnet.taobao.com
来自森大科技官方博客
http://www.cnsendblog.com/index.php/?p=476php

扩展方法使你可以向现有类型“添加”方法,而无需建立新的派生类型、从新编译或以其余方式修改原始类型。 扩展方法是一种特殊的静态方法,但能够像扩展类型上的实例方法同样进行调用。 以上是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();
}ide

此时若是变需求,只须要改写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个赞。动画

什么是扩展方法?
  扩展方法从字面上理解是指扩展的方法,而对应到面向对象编程这个格局中则是指为一个类提供的扩展方法。按照咱们一般的理解,咱们首先须要得到某个类的源代码,而后在这个类代码中增长成员方法,这样就能够达到为一个类提供扩展方法的目的。但是不幸地是,这种方法在没有源代码的状况下就没法奏效了,并且咱们人为地去改变源代码有可能会破坏整个代码的稳定性。那么有没有一种方法能在不改变源代码的前提下为某个类提供扩展方法呢?这就是咱们今天要说的扩展方法,因此咱们能够将扩展方法理解为在不改变源代码的前提下向外部提供扩展方法的一种方式。C#中的扩展方法实现起来是相对来讲比较简单的,例如咱们作在Unity3D游戏开发的时候,可能会用到DOTween这个插件。这个插件是iTween的做者从新编写一个动画插件,效率上比iTween有较大的提高。更为重要的一点是,它采用扩展方法这种实现方式,使得咱们在调用这些API接口的时候难以感受到咱们是在使用一个插件,更像是在使用Unity3D的原生函数,因此当咱们使用DOTween + uGUI 这样的组合的时候,心里会感到无比的舒畅,一切都像是水到渠成通常。
扩展方法有哪些特色?
  扩展方法在实现上和普通的面向对象编程是同样的,换句话说,咱们只须要定义一个类,而后在里面添加并实现相应的方法便可。可是这里须要注意的地方有三点,第一,实现扩展方法的类必须是静态类且类的名称和实现扩展方法的类无关;第2、实现扩展方法的类方法必须是静态方法;第3、实现扩展方法的类方法的第一个参数必须是使用this关键字指明要实现扩展方法的类。例如,咱们知道将一个合法字符串类型转换为整型,可使用int.parse()方法,假如咱们但愿为string类型扩展一个ToInt方法应该怎么办呢?咱们一块儿来看下面的这段代码:网站

  1. /// <summary>
  2. /// 一、定义一个静态类
  3. /// 二、静态类的名称和要实现扩展方法的具体类无关
  4. /// </summary>
  5. public static class SomeClass
  6. {
  7. /// <summary>
  8. /// 三、实现一个具体的静态方法
  9. /// </summary>
  10. /// <param name="str">四、第一个参数必须使用this关键字指定要使用扩展方法的类型</param>
  11. /// <returns></returns>
  12. public static int ToInt(this string str)
  13. {
  14. return int.Parse(str);
  15. }
  16. }
    须要注意的是C#支持扩展方法是从.NET3.5版本开始,因此在编写扩展方法的时候请确保你的.NET版本是否知足这一要求。提到版本问题,有不少朋友尤为是从Unity5.0之后开始学习Unity3D的朋友,经常会在个人博客中留言提到个人代码没法在新环境下运行等等相似地问题,我以为这个世界上更新速度最快的当属IT技术了,你们使用新版本没有问题,但是有时候由于技术发展中的历史遗留问题例如Python2.7和Python三、Unity4.X和Unity5.X,这个时候可能出现版本不兼容的问题,这个时候若是网络上的资源没有及时更新,建议你们仍是及时查看官方的最新文档,由于在博主看来网络上的书籍或者相关文章都是用来参考的,古话说:尽信书不如无书,只有客观、冷静地判断知识的正确与否,咱们方能学到真正有用的知识。
      好了,如今咱们编写完这个扩展方法之后,就能够像下面这样使用扩展方法了:
  17. string str = "1234";
  18. int val = str.ToInt();
    这个示例向你们展现了如何编写一个无参数的扩展方法,那么当咱们须要在扩展方法中传入参数的时候该怎么作呢?咱们只须要在第一个参数后继续加入参数的声明就行了。例如咱们在Unity3D中经常须要给一个3D物体设置坐标,一般咱们能够经过下面的代码来实现:
    transform.position = new Vector3(1,1,1);
    这个代码到目前为止是比较简洁的,但是咱们知道在Unity3D中除了position属性之外还有localPosition属性,若是咱们的代码中再涉及坐标计算的话,我相信这个代码必定会变得很是的长。更有甚者,有时候咱们只想改变三维坐标中的一个维度,但是咱们必须给transform.position一个三维坐标,毫无心外地此时的代码会变得更长。为了解决这个问题,咱们能够扩展出三个方法SetPositionX、SetPositionY、SetPositionZ来分别为x、y、z三个坐标份量进行赋值,咱们继续在SomeClass这个类中添加方法:
  19. /// <summary>
  20. /// 设置Tranform的X坐标
  21. /// </summary>
  22. /// <param name="tran">当前Transform</param>
  23. /// <param name="x">X坐标</param>
  24. public static void SetPositionX(this Transform tran, float x)
  25. {
  26. tran.position = new Vector3(x, tran.position.y, tran.position.z);
  27. }
  28. /// <summary>
  29. /// 设置Tranform的Y坐标
  30. /// </summary>
  31. /// <param name="tran">当前Transform</param>
  32. /// <param name="x">Y坐标</param>
  33. public static void SetPositionY(this Transform tran, float y)
  34. {
  35. tran.position = new Vector3(tran.position.x, y, tran.position.z);
  36. }
  37. /// <summary>
  38. /// 设置Tranform的Z坐标
  39. /// </summary>
  40. /// <param name="tran">当前Transform</param>
  41. /// <param name="x">Z坐标</param>
  42. public static void SetPositionZ(this Transform tran, float z)
  43. {
  44. tran.position = new Vector3(tran.position.x, tran.position.y, z);
  45. }
    使用扩展方法的利弊
      扩展方法使用起来驾轻就熟,因此咱们这里来讨论下使用扩展方法的利弊。好处固然是自由而任性地使用扩展方法对类进行扩展,并且扩展方法在Visual Studio中的智能提示会以蓝色向下箭头进行标识。扩展方法的坏处则是要看设计扩展方法的人可否较好的驾驭这个特性啦,其实全部的技术都是同样的,我经常在游戏群里听到人鄙视Unity3D引擎,以UnReal Engine4为游戏引擎世界里的泰山北斗,我认可UE4的画面效果好,但是能真正用好这个引擎的人有多少呢?扩展方法在使用的时候应该遵照就近原则,便是在最小的范围内使用扩展方法,对具体类而非抽象类实现扩展方法。咱们使用扩展方法无非是由于它在逻辑层须要这样的功能,因此咱们没有必要去改变抽象层的逻辑,由于这样会“污染”整个代码。举一个简单的例子,咱们知道.NET中的基类是object,若是咱们对这个类进行扩展,毫无疑问它会影响全部继承自object的类,这样就会形成“污染”,显然是不可取的。
    小结
    • 在C#中实现扩展方法的类必须是静态类且类的名称和实现扩展方法的类无关
    • 实现扩展方法的类方法必须是静态方法
    • 实现扩展方法的类方法的第一个参数必须是使用this关键字指明要实现扩展方法的类
    • 实现扩展方法应遵照就近原则,在最小的范围内使用扩展方法以免形成“污染”

GPS平台、网站建设、软件开发、系统运维,找森大网络科技!
http://cnsendnet.taobao.com
来自森大科技官方博客
http://www.cnsendblog.com/index.php/?p=476this

相关文章
相关标签/搜索