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

  各位朋友大家好,我是秦元培,欢迎大家关注我的博客。最近偶然接触到了C#中的扩展方法,觉得这个语法特性是一个不错的特性,因此决定在这里系统地对C#中的扩展方法相关内容进行下总结和整理,因为博主觉得学习这件事情本身就是一个积累的过程,所以博主有时候会对现在的线上培训和视频教程这种“在线教育”感到反感。试想《射雕英雄传》中江南七怪远赴大漠传授郭靖武艺苦历十八载,何以难及全真教丹阳子马钰传授内功两年的积累?这里固然有郭靖愚笨木讷的天性和江南七怪武功低微的因素,可是在博主看来更重要的是强调了一个积累。想郭靖一生受益自全真教的玄门内功终成一代“为国为民”的侠之大者,则我辈需更加努力方可在这世间行走奔波。

什么是扩展方法?

  扩展方法从字面上理解是指扩展的方法,而对应到面向对象编程这个格局中则是指为一个类提供的扩展方法。按照我们通常的理解,我们首先需要获得某个类的源代码,然后在这个类代码中增加成员方法,这样就可以达到为一个类提供扩展方法的目的。可是不幸地是,这种方法在没有源代码的情况下就无法奏效了,而且我们人为地去改变源代码有可能会破坏整个代码的稳定性。那么有没有一种方法能在不改变源代码的前提下为某个类提供扩展方法呢?这就是我们今天要说的扩展方法,所以我们可以将扩展方法理解为在不改变源代码的前提下向外部提供扩展方法的一种方式。C#中的扩展方法实现起来是相对来说比较简单的,例如我们做在Unity3D游戏开发的时候,可能会用到DOTween这个插件。这个插件是iTween的作者重新编写一个动画插件,效率上比iTween有较大的提升。更为重要的一点是,它采用扩展方法这种实现方式,使得我们在调用这些API接口的时候难以感觉到我们是在使用一个插件,更像是在使用Unity3D的原生函数,所以当我们使用DOTween + uGUI 这样的组合的时候,内心会感到无比的舒畅,一切都像是水到渠成一般。

扩展方法有哪些特点?

  扩展方法在实现上和普通的面向对象编程是一样的,换句话说,我们只需要定义一个类,然后在里面添加并实现相应的方法即可。但是这里需要注意的地方有三点,第一,实现扩展方法的类必须是静态类且类的名称和实现扩展方法的类无关;第二、实现扩展方法的类方法必须是静态方法;第三、实现扩展方法的类方法的第一个参数必须是使用this关键字指明要实现扩展方法的类。例如,我们知道将一个合法字符串类型转换为整型,可以使用int.parse()方法,假如我们希望为string类型扩展一个ToInt方法应该怎么办呢?我们一起来看下面的这段代码:

/// <summary>
/// 1、定义一个静态类
/// 2、静态类的名称和要实现扩展方法的具体类无关
/// </summary>
public static class SomeClass
{/// <summary>/// 3、实现一个具体的静态方法/// </summary>/// <param name="str">4、第一个参数必须使用this关键字指定要使用扩展方法的类型</param>/// <returns></returns>public static int ToInt(this string str){return int.Parse(str);}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

需要注意的是C#支持扩展方法是从.NET3.5版本开始,所以在编写扩展方法的时候请确保你的.NET版本是否满足这一要求。提到版本问题,有很多朋友尤其是从Unity5.0以后开始学习Unity3D的朋友,常常会在我的博客中留言提到我的代码无法在新环境下运行等等类似地问题,我觉得这个世界上更新速度最快的当属IT技术了,大家使用新版本没有问题,可是有时候因为技术发展中的历史遗留问题例如Python2.7和Python3、Unity4.X和Unity5.X,这个时候可能出现版本不兼容的问题,这个时候如果网络上的资源没有及时更新,建议大家还是及时查看官方的最新文档,因为在博主看来网络上的书籍或者相关文章都是用来参考的,古话说:尽信书不如无书,只有客观、冷静地判断知识的正确与否,我们方能学到真正有用的知识。

  好了,现在我们编写完这个扩展方法以后,就可以像下面这样使用扩展方法了:

string str = "1234";
int val = str.ToInt();
  • 1
  • 2

这个示例向大家展示了如何编写一个无参数的扩展方法,那么当我们需要在扩展方法中传入参数的时候该怎么做呢?我们只需要在第一个参数后继续加入参数的声明就好了。例如我们在Unity3D中常常需要给一个3D物体设置坐标,通常我们可以通过下面的代码来实现:

transform.position = new Vector3(1,1,1);
  • 1

这个代码到目前为止是比较简洁的,可是我们知道在Unity3D中除了position属性以外还有localPosition属性,如果我们的代码中再涉及坐标计算的话,我相信这个代码一定会变得非常的长。更有甚者,有时候我们只想改变三维坐标中的一个维度,可是我们必须给transform.position一个三维坐标,毫无意外地此时的代码会变得更长。为了解决这个问题,我们可以扩展出三个方法SetPositionX、SetPositionY、SetPositionZ来分别为x、y、z三个坐标分量进行赋值,我们继续在SomeClass这个类中添加方法:

/// <summary>
/// 设置Tranform的X坐标
/// </summary>
/// <param name="tran">当前Transform</param>
/// <param name="x">X坐标</param>
public static void SetPositionX(this Transform tran, float x)
{tran.position = new Vector3(x, tran.position.y, tran.position.z);
}/// <summary>
/// 设置Tranform的Y坐标
/// </summary>
/// <param name="tran">当前Transform</param>
/// <param name="x">Y坐标</param>
public static void SetPositionY(this Transform tran, float y)
{tran.position = new Vector3(tran.position.x, y, tran.position.z);
}/// <summary>
/// 设置Tranform的Z坐标
/// </summary>
/// <param name="tran">当前Transform</param>
/// <param name="x">Z坐标</param>
public static void SetPositionZ(this Transform tran, float z)
{tran.position = new Vector3(tran.position.x, tran.position.y, z);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

同样的,我们现在可以直接为一个三维物体的坐标进行赋值:

transform.SetPositionX(1.0f);
transform.SetPositionY(1.0f);
transform.SetPositionZ(1.0f);
  • 1
  • 2
  • 3

使用扩展方法的利弊

  扩展方法使用起来得心应手,所以我们这里来讨论下使用扩展方法的利弊。好处当然是自由而任性地使用扩展方法对类进行扩展,而且扩展方法在Visual Studio中的智能提示会以蓝色向下箭头进行标识。扩展方法的坏处则是要看设计扩展方法的人能否较好的驾驭这个特性啦,其实所有的技术都是一样的,我常常在游戏群里听到人鄙视Unity3D引擎,以UnReal Engine4为游戏引擎世界里的泰山北斗,我承认UE4的画面效果好,可是能真正用好这个引擎的人有多少呢?扩展方法在使用的时候应该遵守就近原则,即是在最小的范围内使用扩展方法,对具体类而非抽象类实现扩展方法。我们使用扩展方法无非是因为它在逻辑层需要这样的功能,所以我们没有必要去改变抽象层的逻辑,因为这样会“污染”整个代码。举一个简单的例子,我们知道.NET中的基类是object,如果我们对这个类进行扩展,毫无疑问它会影响所有继承自object的类,这样就会造成“污染”,显然是不可取的。

小结

  • 在C#中实现扩展方法的类必须是静态类且类的名称和实现扩展方法的类无关
  • 实现扩展方法的类方法必须是静态方法
  • 实现扩展方法的类方法的第一个参数必须是使用this关键字指明要实现扩展方法的类
  • 实现扩展方法应遵守就近原则,在最小的范围内使用扩展方法以避免造成“污染”

C#中的扩展方法学习总结相关推荐

  1. 技术图文:C# 语言中的扩展方法

    背景 前段时间,在知识星球立了一个Flag,在总结 Leetcode 刷题的第五篇图文时遇到了扩展方法 这个知识点,于是先总结一下. 1.扩展方法概述 扩展方法能够向现有类型"添加" ...

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

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

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

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

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

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

  5. MIT18.065 数据分析、信号处理和机器学习中的矩阵方法-学习笔记

    文章目录 MIT18.065 数据分析.信号处理和机器学习中的矩阵方法 Lecture 1 The Column Space of A Contains All Vectors Ax A=CR A=C ...

  6. java中finalizer终结方法学习心得

    最近在看java的中finalizer终结方法,也就是用来释放内存的,但这绝对和C++中的析构函数不相同 C++中的析构函数是用来回收对象所占用的资源的方法,而在java中,当一个对象不可到达时(也就 ...

  7. 在Asp.net MVC framework中使用扩展方法创建Html Helper

    HtmlHelper提供了一些帮助的方法返回一个字符串来生成html. 在System.Web.Mvc.Html命称空间下有一些表单,控件,局部视图Helper方法.我将创建一个生成标签<inp ...

  8. C#学习笔记四: C#3.0自动属性匿名属性及扩展方法

    前言 这一章算是看这本书最大的收获了, Lambda表达式让人用着屡试不爽, C#3.0可谓颠覆了我们的代码编写风格. 因为Lambda所需篇幅挺大, 所以先总结C#3.0智能编译器给我们带来的诸多好 ...

  9. C#参数列表中的this(扩展方法)

    参数列表中this的这种用法是在.NET 3.0之后新增的一种特性---扩展方法.通过这个属性可以让程序员在现有的类型上添加扩展方法(无需创建新的派生类型.重新编译或者以其他方式修改原始类型). 扩展 ...

最新文章

  1. Install Package and Software
  2. BootStrap 效果展示
  3. 保守官僚 诺基亚就这样迷失在智能机时代?
  4. Mysql Explain的简单使用
  5. perl 循环删除指定文件夹下所有满足条件的文件,不包含文件夹
  6. 基于Springboot实现高校社团管理系统
  7. ios wifi 定位_Wifi 定位原理及 iOS Wifi 列表获取(示例代码)
  8. 各省研究与试验发展(R&D)人员全时当量(1998-2018年)
  9. python中timeout什么意思_Python爬虫(五)timeout以及retrying的使用
  10. 基于CTP的期货智能程序化交易系统平台
  11. 计算机学硕答辩,东南大学计算机硕士毕业答辩基本流程(参考).doc
  12. 赏金猎人:德州堕胎法案 | 经济学人早报精选20210902
  13. 解决Chrome或Microsoft Edge浏览器打开时自动跳转到hao123
  14. 微软服务器是永久授权的吗,微软再次针对Office永久授权版套件提价10% 将在10月1日起生效...
  15. Java解析excel工具easyexcel 助你快速简单避免OOM
  16. 接口管理系统 eoLinker-AMS 开源版 V3.5.0 发布更新
  17. ”微信小程序“一场风暴还是过江之鲫
  18. 【20190405】算法-输入一个字符串,按字典序打印出该字符串中字符的所有排列
  19. TM1638驱动数码管的一点建议,附程序
  20. abap SY-INDEX SY-TABIX

热门文章

  1. Pycharm运行项目代码时输入可选参数
  2. Kryo为什么比Hessian快
  3. mac使用codelite运行程序没有输出
  4. Java中遭遇NaN
  5. 如何理解if __name__=='__main__'?
  6. day5 Java中的方法与重载
  7. ndoejs中中间件的使用
  8. android 定制输入法,QQ输入法Android 4.3全新升级 实现私人定制输入
  9. android x86 sleep,如何打开Android X86对houdini的支持
  10. 数据结构折半查找例题_数据结构第9章例题与答案