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

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;
}

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

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

            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, " ", " \t ", " \r\n " }; 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添加一个扩展方法会出现什么效果呢?(未完待续...)

.NET 扩展方法 (一)的更多相关文章

  1. .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法

    .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法 0x00 为什么需要Map(MapWhen)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...

  2. .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类

    .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类 0x00 为什么要引入扩展方法 有的中间件功能比较简单,有的则比较复杂,并且依赖其它组件.除 ...

  3. 为IEnumerable<T>添加RemoveAll<IEnumerable<T>>扩展方法--高性能篇

    最近写代码,遇到一个问题,微软基于List<T>自带的方法是public bool Remove(T item);,可是有时候我们可能会用到诸如RemoveAll<IEnumerab ...

  4. C#的扩展方法解析

    在使用面向对象的语言进行项目开发的过程中,较多的会使用到“继承”的特性,但是并非所有的场景都适合使用“继承”特性,在设计模式的一些基本原则中也有较多的提到. 继承的有关特性的使用所带来的问题:对象的继 ...

  5. 扩展方法(C#)

    扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型.扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用. 下面的示例为String添加 ...

  6. 扩展方法解决LinqToSql Contains超过2100行报错问题

    1.扩展方法 using System; using System.Collections.Generic; using System.Linq; using System.Web; using Sy ...

  7. C#扩展方法

    扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法就相当于一个马甲,给一个现有类套上,就可以为这个类添加其他方法了. 马甲必须定义为stati ...

  8. 枚举扩展方法获取枚举Description

    枚举扩展方法 /// <summary> /// 扩展方法,获得枚举的Description /// </summary> /// <param name="v ...

  9. 扩展方法 1 简单的string扩展方法

    这里是关于 String的简单扩展方法 (静态类 静态方法 this 类型 这里是string) static class Program { static void Main(string[] ar ...

  10. C#中的扩展方法

    扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用. 以上是msdn官网对扩展方 ...

随机推荐

  1. Github上传代码菜鸟超详细教程

      最近需要将课设代码上传到Github上,之前只是用来fork别人的代码. 这篇文章写得是windows下的使用方法. 第一步:创建Github新账户 第二步:新建仓库 第三部:填写名称,简介(可选 ...

  2. 控制ASP.NET Web API 调用频率

    很多的api,例如GitHub’s API 都有流量控制的做法.使用速率限制,以防止在很短的时间量客户端向你的api发出太多的请求.例如,我们可以限制匿名API客户端每小时最多60个请求,而我们可以让 ...

  3. TaintDroid深入剖析之启动篇

    ​1 背景知识 1.1   Android平台软件动态分析现状 众所周知,在计算机领域中所有的软件分析方法都可以归为静态分析和动态分析两大类,在Android平台也不例外.而随着软件加固.混淆技术的不 ...

  4. iOS开发系列--C语言之构造类型

    概述 在第一节中我们就提到C语言的构造类型,分为:数组.结构体.枚举.共用体,当然前面数组的内容已经说了很多了,这一节将会重点说一下其他三种类型. 结构体 枚举 共用体 结构体 数组中存储的是一系列相 ...

  5. Microsoft Azure Web Sites应用与实践【1】—— 打造你的第一个Microsoft Azure Website

    Microsoft Azure Web Sites应用与实践 系列: [1]—— 打造你的第一个Microsoft Azure Website [2]—— 通过本地IIS 远程管理Microsoft ...

  6. maven pom中的repository节点配置没有起作用

    问题描述 昨天晚上想用spring boot快速搭建一个web开发的项目,就打开spring boot的doc,按照说明开始尝试.没想到出师未捷身先死,第一步就挂了. 以下是spring boot的配 ...

  7. jquery做一些小的特效

    在文本框里输入内容到添加到下拉列表里,移除下拉里的内容 1 <!DOCTYPE html> <html> <head> <meta charset=" ...

  8. GitHub的使用记录

    前言: 该贴为笔者在使用GItHub中的一些使用注意,及Git的基本命令,会一直记录笔者在使用GitHub中可能产生的错误及解决方法(会一直更新中),待一些Git初使用者参考,如果有说明不详细或不对的 ...

  9. java笔记——Java关键字static、final使用小结

    static  1. static变量     按照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量:另一种是没有被static修饰的变量,叫实例变量.两者的 ...

  10. Spring学习记录(十)---使用FactoryBean配置Bean

    之前学了,配置bean可以用普通全类名配置.用工厂方法配置,FactoryBean又是什么呢 有时候配置bean要用到,IOC其他Bean,这时,用FactoryBean配置最合适. FactoryB ...