zoukankan      html  css  js  c++  java
  • .NET 扩展方法 (一)

    我还记得刚刚学编程的时候,老师经常会提到一句话:注意空指针。所以经常在某些“入口”位置,进行代码校验,空指针的判断就是其中的一项工作。

    string类型作为常用的数据类型,它在项目中出现的机率极高,所以往往会有如下的代码片段:

                // str 是 string 类型
                if (str == null || str == string.Empty)
                {
                    // ... 其他操作
                    return;
                }
    

    每次都写两个双等号判断,着实有点烦人,让人苦恼不已。在接下来的一段时间内有幸发现了一种新的写法:

                // str 是 string 类型
                if (string.IsNullOrEmpty(str))
                {
                    // ... 其他操作
                    return;
                }
    

    可是有些地方还要判断是否为空格...

                // str 是 string 类型
                if (String.IsNullOrEmpty(str) || str.Trim().Length == 0)
                {
                    // ... 其他操作
                    return;
                }
    

    代码长度又变长了...慢着,别急,.NET 4.0来了...

                // str 是 string 类型
                if (String.IsNullOrWhiteSpace(str))
                {
                    // ... 其他操作
                    return;
                }
    

    该方法很强大,不仅可以判断空格,而且可以判断制表符 ' ' 等空白字符。

    可是... 可是... 我还是觉得不舒服,如果能实现下面的效果该多好呢。

                string str = null;
    
                bool result = str.IsEmpty();
    
                Console.WriteLine(result); // 正常编译通过,正常运行不发生异常,并且输出 True
    

    假设,我们已经通过某些手段使string对象拥有IsEmpty方法:

    如果IsEmpty是实例化方法,str对象为null,此时调用方法必定会引发空指针异常。

    如果IsEmpty是静态方法,按照语法规则,对象是无法调用静态方法的。

    所以,这条路好像行不通啊,怎么办呢?——让扩展方法来解决吧。

    C#编程指南——扩展方法,给出的说明:扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。

    扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用。

    看样子扩展方法很强大啊,那我们该如何实现和调用自定义的扩展方法呢?

    1、因为扩展方法是向现有类型“添加”方法,所以必须有一个类型,这里就是我们想要添加方法的string类型了。

    2、扩展方法也是方法,方法总是需要“载体”的,所以我们需要一个类。对该类的要求有且仅有两点:

    1)是顶级非泛型静态类,2)是对于客户代码而言要有足够的访问权限。

    3、对于扩展方法的要求有四点,除了是静态方法和对于客户代码而言拥有足够的访问权限之外,还要求:

    1)扩展方法的第一个参数必须是将要扩展的类型,这里就是string类型了。2)有且仅有第一个参数必须以this修饰符开头。

    4、写完扩展方法,引入相应的命名空间(如果需要),根据VS的智能敏感提示,然后写代码调用即可。 

    Demo:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace MethodDemo
    {
        public static class StringExtentsion
        {
            public static bool IsEmpty(this string str)
            {
                return string.IsNullOrWhiteSpace(str);
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                string[] arr = new string[] { null, string.Empty, " ", "  	  ", "   
       " };
    
                foreach (string str in arr)
                {
                    bool result = str.IsEmpty();
    
                    Console.WriteLine(result); // 编译通过,运行无异常,并且全部输出True
                }
                
                Console.Read();
            }
        }
    }
    

      

    让我们仔细看一下这个demo吧,哇塞,对象竟然可以调用静态方法了,这完全打破了以往的语法规则啊。是这样吗?让我们以怀疑的心态一探究竟。

    我们利用 VS自带的IL反汇编程序,反编译一下,看一看MSIL代码。StringExtentsion类的IsEmpty方法签名如下:

    .method public hidebysig static bool  IsEmpty(string str) cil managed 
    {
    } 
    
    我们可以从中找到熟悉的影子 public static bool IsEmpty(string str){},它和一个标准的静态方法无异,this 修饰符在这时候已经 “消失” 了。

     再看一下客户代码吧:

      IL_003b:  call       bool MethodDemo.StringExtentsion::IsEmpty(string)
    

     即便你看不懂MSIL代码,我想你也有可能推测出正确结果——没错,我们被编译器“欺骗”了,以下两种写法是等效的:

         result = str.IsEmpty();
    
         result = StringExtentsion.IsEmpty(str); // 此时 扩展方法中的this修饰符是可有可无的
    

      

     看到这里,对扩展方法已经有了一个大概了解,我们再回头看一下 C#编程指南——扩展方法,中给出的一句说明:

    扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。扩展方法是一

    种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用。

    1、在这里“添加”两个字被加了双引号,故名其意不是真正的添加,扩展方法还存在于其定义的静态类中,编译后的方法签名和标准的静态方法无差异,

    this修饰符、在这时候已经消失了。

    2、扩展方法是一种特殊的静态方法,其特殊在于其语法规则可保证编译器可以将“扩展类型的对象调用静态方法(扩展方法)”这种语法表象 编译通过。 

      可以想象一下,编译器在编译的时候,它要查找当前代码文件域所引入的命名空间下的所有扩展方法、其工作量是很大的(更多参见:ExtensionAttribute)。

    后记:

    1、这次举的这个例子很特殊,能将扩展方法的绝对威力展示出来:

    1)string是.NET 类库中的类,我们不能修改string类吧。

    2)string是密封类,不能继承。

    3)避免空指针异常,按语法规则最便捷的方式就是通过静态方法的参数去解决,就像 string.IsNullOrWhiteSpace 方法一样,

    可是想得到的形式却是对象调用实例方法。

     

     2、如果给object添加一个扩展方法会出现什么效果呢?(未完待续...)

  • 相关阅读:
    c中uint32转为string
    linux中查找某类文件中的特定字符串
    VMWare Workstation 无法连接外部设备
    Evernote(印象笔记)无法登录的问题
    Python request 在linux上持续并发发送HTTP请求遇到 Failed to establish a new connection: [Errno 11] Resource temporarily unavailable
    设计模式
    jquery-ui sortable 在拖动换位置时改变元素的大小导致占位与实际不一致
    Appium IOS 使用多模拟器并发执行测试
    Fiddler脚本修改Response数据
    android style和attr的用法
  • 原文地址:https://www.cnblogs.com/08shiyan/p/3939635.html
Copyright © 2011-2022 走看看