C# this关键字(给底层类库扩展成员方法)

本文参考自唔愛吃蘋果C#原始类型扩展方法—this参数修饰符,并在其基础上做了一些细节上的解释

1、this作为参数关键字的作用

使用this关键字,可以向this关键字后面的类型添加扩展方法,而无需给其创建新的派生类型、重新编译或以其他的方式修改类型.

扩展方法是一种特殊的静态方法,但可以像实例方法那样调用。但是this关键字最主要的作用是对类型的重载方法的扩充,来满足自身的需求,因为有些类方法的重载方法可能不是很完善,而直接修改类型的条件不足(应为可能有些已经被编译成dll,有些测试.net框架的底层类),所以只能通过this关键字对其进行扩展,也就是完善类方法的重载方法。

说了这么多,可能你还是不理解,现在有个需求:

我想利用string.format拼接一个,异常字符串,具体内容是:   ("parameter {0} cannot be empty",parameter),我知道使用string.format能很好地胜任,但是string.format静态方法我用不习惯,所以我想将它改造为string类的实例方法,直接通过"".实例方法来调用,最后的效果就是:"parameter {0} cannot be empty".实例方法名(parameter)

但是我不可能修改string类,来达到这个目地,因为string类是.Net Framework的底层类库,所以只能使用this关键字,来给其添加扩展方法,代码如下:

public static class StringUtilities
{
  public static string FormatWith(this string format,IFormatProvider provider,object org0) {
            return format.FormatWith(provider, new object[] { org0 });
  }
  public static string FormatWith(this string format, IFormatProvider provider, object[] args) {
            return string.Format(provider,format,args);
  }
}

ok,现在通过this关键字给string类添加了两个实例重载方法,但是需要注意,这里的类必须就静态类,扩展方法必须是静态方法,原因如下:

(1)、这里传入的需要扩展的string类型

不是静态变量而是成员变量

(2)、静态类的特点,如果一个静态类没有加构造函数,那么编译器会自动的给它加一个静态构造函数,静态构造函数是最早被调用的,只要有静态访问,那就先调用静态构造函数,接着调用非静态构造函数,而且静态类里面的成员在第一次被访问之后,就会被添加到全局环境中,后面的访问,将不会执行初始化操作,直接调用即可。而且静态类中不能有成员变量,this关键字是个列外

(3)、当类是静态类时,程序会在编译的时候,就将所有的静态成员编译到全局环境中,当类不是静态类的时候,只有当类中的静态成员被调用之后,才会被初始化到全局环境中,也就是说,代码如下:

public  class StringUtilities
{
     public static string FormatWith(this string format, IFormatProvider provider, object org0)
     {
         return format.FormatWith(provider, new object[] { org0 });
     }
}

这里的StringUtilities不是静态类,所以只要当StringUtilities的FormatWith在被初始化之后,他才会被初始化到全局环境中,下一次调用就不需要初始化了直接去全局环境中取,所以这个时候

这样是调不到FormatWith方法的,应为此时的FormatWith方法还没有被初始化,所以编译器会报错

,但是如果将StringUtilities改为静态类,那么编译器就会在编译完后,就将所有的静态成员初始化到全局环境中,这样上面出错的代码就没问题了,代码如下:

    public static class StringUtilities
    {

        public static string FormatWith(this string format, IFormatProvider provider, object org0)
        {
            return format.FormatWith(provider, new object[] { org0 });
        }

        public static string FormatWith(this string format, IFormatProvider provider, params object[] args)
        {
            DataValidate.ArgumentNotNull(format, "format");
            return string.Format(provider, format, args);
        }
    }

2、ok,上面的代码完成了对string类的扩展,为其添加了两个扩展方法,下面通过代码来测试是否成功

 string result = "'{0}' cannot empty".FormatWith(CultureInfo.InvariantCulture, "aaa");
 Response.Write(result);

输出:

ok,说明实例方法扩展成功

总结:上面的扩展方法的调用方式,看上去像是成员方法,但实际编译器会对this关键字做特殊处理,编译器生成的中间语言(IL)会将代码转换为对静态方法的调用,

因此,并未真正违反封装原则。实际上,扩展方法无法访问它们所扩展的类型中的私有变量,不信你可以试试在扩展方法中访问string的私有成员!!!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏北京马哥教育

17个案例带你3分钟搞定Linux正则表达式

正则表达式是一种字符模式,用于在查找过程中匹配制定的字符。 元字符通常在Linux中分为两类: Shell元字符,由Linux Shell进行解析; 正则表达式...

36040
来自专栏LEo的网络日志

python技巧分享(六)

29960
来自专栏python3

python3--函数初识

函数能提高应用的模块性,和代码的重复利用率。已经知道python提高了许多内建函数,比如print(),len()等。但你也可以自己创建函数,这被叫做用户自定义...

13210
来自专栏决胜机器学习

《Redis设计与实现》读书笔记(五) ——Redis中的整数集合

《Redis设计与实现》读书笔记(五) ——Redis中的整数集合 (原创内容,转载请注明来源,谢谢) 一、概述 整数集合(intset)是redis数据结构集...

35940
来自专栏前端儿

大小写互换

  现在给出了一个只包含大小写字母的字符串,不含空格和换行,要求把其中的大写换成小写,小写换成大写,然后输出互换后的字符串。

14020
来自专栏Python专栏

17个案例带你3分钟搞定Linux正则表达式

来源:https://blog.ansheng.me/article/examples-of-linux-regular-expressions

18830
来自专栏Phoenix的Android之旅

动态代理-进阶高级开发必学技能

关于代理模式的话题有很多, 在开发中经常用到的应该是静态代理模式,能很好的去耦合。 动态代理是代理模式的另外一种实现。

9330
来自专栏用户2442861的专栏

深入 char * ,char ** ,char a[ ] ,char *a[] 内核

http://blog.csdn.net/daiyutage/article/details/8604720

19620
来自专栏PhpZendo

PHP 合并数组运算符 + 与 array_merge 函数

在 php 中对两个数组进行合并运算,通常使用 array_merge 和 加号(+)运算符,他们的区别是什么呢?先让我们看看下面的测试用例

12010
来自专栏Hongten

java多线程系列_用Thread类创建线程(2)

在Java中创建线程有两种方法:使用Thread类和使用Runnable接口。在使用Runnable接口时需要建立一个Thread实例。因此,无论是通过Thre...

11330

扫码关注云+社区

领取腾讯云代金券