您的位置:首页 > 编程语言 > C#

C# 为类型扩展方法

2010-01-08 16:50 176 查看


声明:本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);
}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐