[C# 基础知识系列]专题十五:全面解析扩展方法
- class Program
- {
- /// <summary>
- /// 扩展方法演示
- /// </summary>
- /// <param name="args"></param>
- static void Main(string[] args)
- {
- #region 演示扩展方法的使用
- // 调用扩展方法
- WebRequest request = WebRequest.Create("http://www.cnblogs.com");
- using (WebResponse response = request.GetResponse())
- {
- using(Stream responsestream =response.GetResponseStream())
- {
- using (FileStream output = File.Create("response.htm"))
- {
- // 调用扩展方法
- responsestream.CopyToNewStream(output);
- Console.Read();
- }
- }
- }
- #endregion
- }
- }
- /// <summary>
- /// 扩展方法必须在非泛型静态类中定义
- /// </summary>
- public static class StreamExten
- {
- // 定义扩展方法
- // 该扩展方法实现从一个流中内容复制到另一个流中
- public static void CopyToNewStream(this Stream inputstream, Stream outputstream)
- {
- byte[] buffer = new byte[8192];
- int read;
- while ((read = inputstream.Read(buffer, 0, buffer.Length)) > 0)
- {
- outputstream.Write(buffer, 0, read);
- }
- }
- }
- 它必须在一个非嵌套、非泛型的静态类中
- 它至少要有一个参数
- 第一个参数必须加上this关键字作为前缀(第一个参数类型也称为扩展类型,即指方法对这个类型进行扩展)
- 第一个参数不能用其他任何修饰符(如不能使用ref out等修饰符)
- 第一个参数的类型不能是指针类型
- View Code
- class Program
- {
- /// <summary>
- /// 扩展方法必须在非泛型静态类中定义
- /// </summary>
- public static class StreamExten
- {
- // 定义扩展方法
- // 该扩展方法实现从一个流中内容复制到另一个流中
- public static void CopyToNewStream(this Stream inputstream, Stream outputstream)
- {
- byte[] buffer = new byte[8192];
- int read;
- while ((read = inputstream.Read(buffer, 0, buffer.Length)) > 0)
- {
- outputstream.Write(buffer, 0, read);
- }
- }
- }
- /// <summary>
- /// 扩展方法演示
- /// </summary>
- /// <param name="args"></param>
- static void Main(string[] args)
- {
- #region 演示扩展方法的使用
- // 调用扩展方法
- WebRequest request = WebRequest.Create("http://www.cnblogs.com");
- using (WebResponse response = request.GetResponse())
- {
- using(Stream responsestream =response.GetResponseStream())
- {
- using (FileStream output = File.Create("response.htm"))
- {
- // 调用扩展方法
- responsestream.CopyToNewStream(output);
- Console.Read();
- }
- }
- }
- #endregion
- }
- }
- using System;
- namespace 扩展方法如何被发现Demo
- {
- // 要使用不同命名空间的扩展方法首先要添加该命名空间的引用
- using CustomNamesapce;
- class Program
- {
- static void Main(string[] args)
- {
- Person p = new Person { Name = "Learning hard" };
- // 当类型中包含了实例方法时,VS中的智能提示就只会列出实例方法,而不会列出扩展方法
- // 当把实例方法注释掉之后,VS的智能提示中才会列出扩展方法,此时编译器在Person类型中找不到实例方法
- // 所以首先从当前命名空间下查找是否有该名字的扩展方法,如果找到不会去其他命名空间中查找了
- // 如果在当前命名空间中没有找到,则会到导入的命名空间中再进行查找
- p.Print();
- p.Print("Hello");
- Console.Read();
- }
- }
- // 自定义类型
- public class Person
- {
- public string Name { get; set; }
- // 当类型中的实例方法
- public void Print()
- {
- Console.WriteLine("调用实例方法输出,姓名为: {0}", Name);
- }
- }
- // 当前命名空间下的扩展方法定义
- public static class Extensionclass
- {
- /// <summary>
- /// 扩展方法定义
- /// </summary>
- /// <param name="per"></param>
- public static void Print(this Person per)
- {
- Console.WriteLine("调用的是同一命名空间下的扩展方法输出,姓名为: {0}", per.Name);
- }
- }
- }
- namespace CustomNamesapce
- {
- using 扩展方法如何被发现Demo;
- public static class CustomExtensionClass
- {
- /// <summary>
- /// 扩展方法定义
- /// </summary>
- /// <param name="per"></param>
- public static void Print(this Person per)
- {
- Console.WriteLine("调用的是不同命名空间下扩展方法输出,姓名为: {0}", per.Name);
- }
- /// <summary>
- /// 扩展方法定义
- /// </summary>
- /// <param name="per"></param>
- public static void Print(this Person per,string s)
- {
- Console.WriteLine("调用的是不同命名空间下扩展方法输出,姓名为: {0}, 附加字符串为{1}", per.Name, s);
- }
- }
- }
- using System;
- namespace 在空引用上调用方法Demo
- {
- // 必须引入扩展方法定义的命名空间
- using ExtensionDefine;
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("空引用上调用扩展方法演示:");
- string s = null;
- // 在该程序中要使用扩展方法必须通过using来引用
- // 在空引用上调用扩展方法不会发生NullReferenceException异常
- // 之所以不会出现异常,是因为在空引用上调用扩展方法,对于编译器而言只是把空引用s当成参数传入静态方法中而已
- // 对于编译器来说,s.IsNull()的调用等效于下面的代码
- //Console.WriteLine("字符串S为空字符串:{0}", NullExten.IsNull(s));
- Console.WriteLine("字符串S为空字符串:{0}", s.IsNull());
- Console.ReadKey();
- }
- }
- }
- namespace ExtensionDefine
- {
- /// <summary>
- /// 扩展方法定义
- /// </summary>
- public static class NullExten
- {
- // 此时扩展的类型为object,这里我是故意用object类型的
- // 如果是为了演示,当我们为一个类型定义扩展方法时,应尽量扩展具体类型,如果扩展其基类的话
- // 则所有继承于基类的类型都将具有该扩展方法,这样对其他类型来说就进行了“污染
- // 子所以形成了污染,是因为我们定义的扩展方法的意图本来只想扩展某个子类。
- // 其实下面这个方法我的意图只是想扩展string类型的,所以更好的定义方法如下:
- //public static bool isNull(this string str)
- //{
- // return str == null;
- //}
- // 不规范定义扩展方法的方式
- public static bool IsNull(this object obj)
- {
- return obj == null;
- }
- }
- }
- .method private hidebysig static void Main(string[] args) cil managed
- {
- .entrypoint
- // 代码大小 43 (0x2b)
- .maxstack 2
- .locals init ([0] string s)
- IL_0000: nop
- IL_0001: ldstr bytearray (7A 7A 15 5F 28 75 0A 4E 03 8C 28 75 69 62 55 5C // zz._(u.N..(uibU\
- B9 65 D5 6C 14 6F 3A 79 1A FF ) // .e.l.o:y..
- IL_0006: call void [mscorlib]System.Console::WriteLine(string)
- IL_000b: nop
- IL_000c: ldnull
- IL_000d: stloc.0
- IL_000e: ldstr bytearray (57 5B 26 7B 32 4E 53 00 3A 4E 7A 7A 57 5B 26 7B // W[&{2NS.:NzzW[&{
- 4E 1A FF 7B 00 30 00 7D 00 ) // 2N..{.0.}.
- IL_0013: ldloc.0
- IL_0014: call bool ExtensionDefine.NullExten::IsNull(object)
- IL_0019: box [mscorlib]System.Boolean
- IL_001e: call void [mscorlib]System.Console::WriteLine(string,
- object)
- IL_0023: nop
- IL_0024: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
- IL_0029: pop
- IL_002a: ret
- } // end of method Program::Main
- 介绍了扩展方法的定义和使用,以及扩展方法定义的规则,具体可以参照第一部分
- 介绍了编译器是如何去发现扩展方法的,以及写了一些例子进行测试,具体可以参照第二部分
- 解释了为什么在空引用中可以调用扩展方法的原因,具体可以参照第三部分
附件:http://down.51cto.com/data/2361989
本文转自LearningHard 51CTO博客,原文链接:http://blog.51cto.com/learninghard/1092482,如需转载请自行联系原作者
[C# 基础知识系列]专题十五:全面解析扩展方法相关推荐
- [C#基础知识系列]专题十二:迭代器
引言: 在C# 1.0中我们经常使用foreach来遍历一个集合中的元素,然而一个类型要能够使用foreach关键字来对其进行遍历必须实现IEnumerable或IEnumerable<T> ...
- [C#基础知识系列]专题十:全面解析可空类型
引言: C# 2.0 中还引入了可空类型,可空类型也是值类型,只是可空类型是包括null的值类型的,下面就介绍下C#2.0中对可空类型的支持具体有哪些内容(最近一直都在思考如何来分享这篇文章的,因为刚 ...
- [C# 基础知识系列]专题十四:深入理解Lambda表达式
引言: 对于刚刚接触Lambda表达式的朋友们,可能会对Lambda表达式感到非常疑惑,它到底是个什么什么样的技术呢?以及它有什么好处和先进的地方呢?下面的介绍将会解除你这些疑惑. 一.Lambda表 ...
- [C#基础知识系列]专题十:全面解析可空类型[转]
原文链接 主要内容: 1:空合并操作符(?? 操作符) ??操作符也就是"空合并操作符",它代表的意思是两个操作数,如果左边的数不为null时,就返回左边的数,如果左边的数为nul ...
- 5G基础知识学习(十五)—NSA手机的5G信号是怎么显示的?
5G基础知识学习(十五)-NSA手机的5G信号是怎么显示的? 参考网址:http://www.txrjy.com/thread-1106049-1-1.html 看完了前面的连载,相信大家对NSA也就 ...
- [C#基础知识系列]专题十七:深入理解动态类型
本专题概要: 动态类型介绍 为什么需要动态类型 动态类型的使用 动态类型背后的故事 动态类型的约束 实现动态行为 总结 引言: 终于迎来了我们C# 4中特性了,C# 4主要有两方面的改善--Com 互 ...
- [C# 基础知识系列]专题五:当点击按钮时触发Click事件背后发生的事情
引言: 当我们在点击窗口中的Button控件VS会帮我们自动生成一些代码,我们只需要在Click方法中写一些自己的代码就可以实现触发Click事件后我们Click方法中代码就会执行,然而我一直有一个疑 ...
- 【转】[C# 基础知识系列]专题四:事件揭秘
引言: 前面几个专题对委托进行了详细的介绍的,然后我们在编写代码过程中经常会听到"事件"这个概念的,尤其是写UI的时候,当我们点击一个按钮后VS就会自动帮我们生成一些后台的代码,然 ...
- [C# 基础知识系列]专题六:泛型基础篇——为什么引入泛型
引言: 前面专题主要介绍了C#1中的2个核心特性--委托和事件,然而在C# 2.0中又引入一个很重要的特性,它就是泛型,大家在平常的操作中肯定会经常碰到并使用它,如果你对于它的一些相关特性还不是很了解 ...
最新文章
- 吴恩达机器学习笔记 —— 18 大规模机器学习
- SpringBoot 配置 generator代码生成+knife4j接口文档(2种模板设置、逻辑删除、字段填充 含代码粘贴可用)保姆级教程(注意事项+建表SQL+代码生成类封装+测试类)
- Java判断字符串既不等于A也不等于B
- 介绍 Spring 3.1 M1 中的缓存功能
- Qt 设置应用程序开机自启动
- 董明珠:10个亿不要了,还想再赌五年 雷军:可以试一下
- Err CLSU-00104: additional error information: need ha priv
- Now, using the touch-screen smartphone in your hand
- 如何利用PS动作一秒将字体生成逼真刺绣效果
- 工作两三年了,整不明白架构图都画啥?
- 饿了么推荐系统:从0到1
- python3 排列组合
- ssh远程登录命令简单实例
- XMLHttpRequest对象的readyState与status
- keepalived+LVS;keepalived+nginx
- 【Unity】预计算刚体运动轨迹
- 项目经理的职业规划,建议收藏
- 项目经理杂事多,该怎么有效的安排时间
- 【苹果CMS技术教程】苹果CMSV10基础安装过程,如何拥有自己的视频网站
- 朋友圈不知你看到的那么简单,千万Feed流系统的存储技术解密
热门文章
- python类定义中__init__()_转:python学习——类中为什么要定义__init__()方法
- java ee8 mvc1_JavaEE——SpringMVC(1)--@RequestMapping
- linux shell 脚本路径,linux获取shell脚本所在绝对路径操作介绍
- docker镜像和容器的导出导入
- edittext 无法输入内容_掌握其中1个Excel小技巧,你就不用再担心会重复录入内容了。...
- CSS cursor 属性-鼠标形状
- Lesson Plan 教学计划 翻译
- 《天天数学》连载33:二月二日
- Spring Boot基础学习笔记10:配置国际化页面
- SSM框架笔记09:初探Spring——采用Java配置方式