C# 为类型扩展方法

来源:互联网 发布:手机智能对话软件 编辑:程序博客网 时间:2024/05/16 01:45

 

声明:本CSDN博客中的所有文章均为本人原创 请勿转载

C# 类型扩展方法

什么是扩展方法?

扩展方法使您能够向现有类型(或接口) 添加 方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。扩展方法是一种特殊的静态方法 ,但可以像扩展类型 上的实例方法一样进行调用。对于用 C# Visual Basic 编写的客户端代码,调用扩展方法与调用在类型中实际定义的方法之间没有明显的差异。(源于 MSDN

1 )扩展方法的创建

      首先需要定义一个准备包含扩展方法的静态类

Public class EnlargeClass   {

         // 加入扩展方法

}  

      其次,向该类添加一个静态的方法

        该方法的第一个参数必须以   this 修饰符开头。形参为 需要将该方法绑定到的类型。这一参数不需要使用者在调用处显式提供。接下来的形参则根据方法需要添加。

如:

  public static returnType   MethodName (this ClientClass refObj , // 由编译器识别并填充

                                  parameterType   parameter // 由调用者使用的参数

                                  ……

                                 ) 

   注: 1. ClientClass 表示你要绑定到的类型。编译器根据这一类型来决定该方法绑定到那种类型上。

          refObj 表示当前的对象。即调用者的实例的一个引用。

        2. 指示绑定到的类型的参数必须由 this 修饰。从这一点可以看出。 This 关键字表示了 EnlargeClass 在当前的上下文的一个引用。

         注意: refObj 并不是一个指向同一对象的指针。它是一个原对象的引用复本,是否能够影响到原对象取决于原对象的类型(引用或者值类型)。

        3. 指示类型绑定的参数必须处于该方法的第一个位置。 这样编译器不会关注下面的参数列表。否则将不能通过编译。

         4. 在创建扩展方法时,需要保证该方法对使用点是可访问的。

          5. 如果定义了一个和原类成员相同的扩展方法,则编译器优先于原类型方法。所以,编写扩展方法时要注意不能和原类方法重名。

   

可以向 .net 的所有类型和自定义的类型添加扩展方法。

在扩展方法的静态类中,可以为多个类型绑定方法。

为什么语言设计者要使用静态形式绑定方法呢?和程序的入口 Main 函数一样,静态的调用不容易受到对类型构造的考虑和影响。但编程者却需要注意访问权限的修饰。

 

 

为了考察一下你的理解回答一个问题。能不能将 string ,char,baty,int 等基本数据类型进行方法扩展?并解释原因。

 

2 )扩展方法的调用

  扩展方法的调用是使用原被扩展的类型的实例 来调用的。从表面看,对象调用静态方法是乎不合常理。事实上在被编译器编译为 IL 时会自动转换为对扩展类静态方法的调用。

  扩展方法并不属于原类型中的成员。它只是一种外接的功能。所以,扩展方法无法访问原类型的内部私有成员 。但扩展方法是否可以操作原类的公共属性呢?根据上面的理解,你应该能很回答这个问题。如果还不清楚,请尝试写几个小示例。答案就不用公布了。

 

调用一个扩展方法的步骤如下:

首先需要使扩展类在当前环境下可见。如果扩展方法创建在其它命名空间,请引入该命名空间。

       当引入扩展类的命名空间时,编译器就会在检查时对你所扩展的类型加入创建的静态方法。事实上,系统并没有真正的向原类添加任何函数成员。只是将当前可见的该类型产生的所有对象绑定了该方法。

  例如:使用上面创建的扩展

      假设 ClientClass 类为 .net 定义的 Int

      那么, Int32 myInt=new Int();

       这样, myInt 就拥有了 MethodName 方法。

       myInt. MethodName(parameter); 调用即可。

   其次,在这一类型的实例中像使用该类型定义的非静态 成员一样使用它。

首先编译器会查找原类型的函数成员,如果没有该函数签名,则查找扩展类的成员,因此,如果扩展方法与原类方法签名相同,则系统将不会调用扩展方法。

 

扩展方法可以在原类型内部中像自己的函数成员一样调用。原因是:虽然并没有真正绑定到该类型上,但绑定了类的 this 指针指向的成员。例如测试示例中的 Study 方法内部,就使用了扩展方法。

 

应用范围:

  除非在无法对原有类进行修改的情况下,否则 Microsoft 不建议使用增加扩展的方法。应当使用继承等方式进行类型扩展,以使系统达到良好清晰的结构。

 

最后留给一个问题,能不能将扩展方法变为泛型方法?

 

 

[测试示例源码]

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace ConsoleEnlargeClassSpace

{

    /// <summary>

    /// 扩展类

    /// </summary>

    public static class myEnlargeClass

    {

        /// <summary>

        /// 扩展string 类型

        /// :用来去除字符串中的空格

        /// </summary>

        /// <param name="str"></param>

        /// <returns> string </returns>

        public static   string ExorciseSpacebar(this String str)

        {

            return str.Replace(" " , "" );

        }

 

        /// <summary>

        /// 扩展string 类型

        /// :用于比较两个字符串对象值是否相同。

        /// </summary>

        /// <param name="str"></param>

        /// <param name="aimStr"> 用于比较的字符串对象 </param>

        /// <returns> bool </returns>

        public static bool   CompareString(this String str,String aimStr)

        {

            if (str.ToString() == aimStr.ToString())

                return true ;

            else

                return false ;

        }

        /// <summary>

        /// 扩展int

        /// :用于得到int 对象的长度

        /// </summary>

        /// <param name="myInt"></param>

        /// <returns></returns>

        public static Int32   getLength(this Int32   myInt)

        {

 

           return myInt.ToString().Length;

 

            /* 测试引用和值类型的区别

            int length = myInt.ToString().Length;

            myInt = 23554;

            return length;

             * */

        }

        /// <summary>

        /// * 测试引用和值类型的区别

        ///

        /// </summary>

        /// <param name="people"></param>

        /// <returns></returns>

        public static void   sayName(this ProgramSpace.People people,string reName)

        {

            Console .WriteLine("I change the name:my name is " + (people.Name = reName));

        }

    }

  

}

 

namespace ProgramSpace

{

    // 引用扩展类

    using ConsoleEnlargeClassSpace;

 

    class Program

    {

        static void Main(string [] args)

        {

 

            String sourceStr = "hello,I am the architect ." ;

 

            // call the ExorciseSpacebar method

 

            Console .WriteLine(" 字符串为:" + sourceStr);

 

            Console .WriteLine(" 原字符串长度为:" + sourceStr.Length);

 

            Console .WriteLine(" 去掉空格之后的长度为:" + sourceStr.ExorciseSpacebar().Length );

            

            // call the CompareString method

 

            // 注:比较同一个String 对象

 

            Console .WriteLine(sourceStr.CompareString(sourceStr));

 

 

            Int32    myInt=0;

 

            Console .WriteLine ( myInt.getLength ());

 

            //Console.WriteLine(myInt.ToString().Length);

 

            for (int i = 0; i < 20; i++, Console .Write("-" )) ;

            /**

             * 向自定义类型添加扩展

             * */

            People people = new People ();

 

            Console .WriteLine("/n my name is " + people.Name);

 

            people.sayName("Acess" );

            people.Study("Assert!" );

         

        }

    }

 

    public class People

    {

        private string name="Assert" ;

        // 名字

        public string Name

        {

            get { return name; }

            set { name = value ; }

        }

 

        public void Study(string reName)

        {

            Console .WriteLine("I can learn anything..." );

            this .sayName(reName);

        }

 

 

    }

 

}

 

原创粉丝点击