C#教程:声明和调用扩展方法


声明扩展方法

我们并不能将任何的方法都作为扩展方法——扩展方法必须要有以下的一些特性:

  • 它必须是被包含在一个非嵌套的, 非泛型的静态类当中(因此必须是静态方法)
  • 必须至少拥有一个参数
  • 第一个参数必须是由this关键字开头
  • 第一个参数不能有其他的修饰符, 例如out / ref
  • 第一个参数类型不能是一个指针类型

扩展方法本身可以是泛型的, 可以有返回值, 除了第一个参数外, 也可以包含ref / out参数, 可以作为partial类的一部分, 可以在迭代块当中来实现, 可以使用nullable类型——任何语法, 只要遵循了上述的约束.

我们把方法的第一个参数类型叫做extended type(被扩展的类型). 这并不是一个官方术语, 不过是一个有用的简短表达方式.

上面的列表不仅仅提供了所有的限制, 同时也表明了将静态方法变为扩展方法你需要做的步骤——加上this关键字. 以下的代码将我们之前的例子改造为扩展方法:

   1: public static class StreamUtil

 

   2: {

 

   3: const int BufferSize = 8192;

 

   4: public static void CopyTo(this Stream input,

 

   5: Stream output)

 

   6: {

 

   7: byte[] buffer = new byte[BufferSize];

 

   8: int read;

 

   9: while ((read = input.Read(buffer, 0, buffer.Length)) > 0)

 

  10: {

 

  11: output.Write(buffer, 0, read);

 

  12: }

 

  13: }

 

  14: public static byte[] ReadFully(this Stream input)

 

  15: {

 

  16: using (MemoryStream tempStream = new MemoryStream())

 

  17: {

 

  18: CopyTo(input, tempStream);

 

  19: return tempStream.ToArray();

 

  20: }

 

  21: }

 

  22: }

相比之前的例子, 我紧紧增加了两个this修饰符, 同时将方法名称从Copy改为CopyTo. 虽然现在在ReadFully当中看起来有点奇怪, 不过之后我们会看到这个改动会让我们的调用代码看起来更加自然.

调用扩展方法

简单来说, 改造实例代码来使用StreamUtil和改造该工具类一样简单. 这次, 我们不是要增加什么代码, 相反, 我们要去掉一些代码. 下面的代码使用我们提过的新的”语法”来调用CopyTo. 我说”新”实际上它根本就不新——因为它和我们一直使用的调用实例方法的语法一模一样.

   1: WebRequest request = WebRequest.Create("http://manning.com");
   2: using (WebResponse response = request.GetResponse())
   3: using (Stream responseStream = response.GetResponseStream())
   4: using (FileStream output = File.Create("response.dat"))
   5: {
   6:     responseStream.CopyTo(output);
   7: }

在上面的代码中, 至少它看起来像是我们让reponse流来完成copying的操作. 实际上幕后依然是StreamUtil在完成实际的工作, 但代码读起来更加自然了. 编译器在背后实际上仅仅是将CopyTo的调用转到了对StreamUtil.CopyTo的调用, 并传递responseStream作为方法的第一个参数.

你可能会注意并没有什么特别的东西指示我们到底是正在调用Stream的扩展方法还是常规的实例方法. 如果使用VS2008, 当你把鼠标移到一个方法调用上面的时候, 如果它是一个扩展方法, 那么将会出现一个明显的提示. 另外智能提示也会帮你指出哪些方法是扩展方法, 一个向下的箭头图标会出现在扩展方法前. 当然我们并不需要仔细到观察每一个方法来了解它是不是扩展方法, 因为多数情况下, 我们并不关心我们正在调用的到底是一个扩展方法还是一个实例方法.

在我们调用代码中, 还有一件可能会让人感到奇怪的事情, 那就是——StreamUtil根本就没有不提到! 编译器是怎么知道我们是要使用扩展方法的呢? 待续!



相关阅读:
ACCESS集锦
SQL2005的默认端口的修改方法
正确修改Linux的系统时间
GD输出汉字的函数的分析
JavaScript实现Sleep函数的代码
Windows回收站高效使用技巧
页面(PAGE)标记(TAGS)
利用配置文件实现SQL Server与Oralce访问类的转换
ASP.NET中MD5与SHA1加密的几种方法
asp文本框换行显示代码
原创]javascript代码在ie8里报错 document.getElementById(...) 为空或不是对象的解决方法" target="_blank">[原创]javascript代码在ie8里报错 document.getElementById(...) 为空或不是对象的解决方法
如何像table一样对层div进行轻松布局
PHP5 安装方法
JS暴虐查找法简洁版
快速导航

Copyright © 2016 phpStudy |