分享
 
 
 

C# 3.0 新特性:扩展方法初探

王朝c#·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

C#3.0中一个激动人心的特性就是扩展方法:你可以使用实例方法的语法来调用静态方法。本文仔细阐述了这一新特性并且给出了几个相应的例子。

声明扩展方法

扩展方法的行为和静态方法是非常类似的,你只能在静态类中声明它们。为声明一个扩展方法,你需要给该方法的第一个参数指定this关键字,如下例:

// Program.cs

public static class EMClass

{

public static int ToInt32Ext(this string s)

{

return Int32.Parse(s);

}

public static int ToInt32Static(string s)

{

return Int32.Parse(s);

}

}

class Program

{

static void Main(string[] args)

{

string s = "9";

int i = s.ToInt32Ext(); // LINE A

Console.WriteLine(i);

int j = EMClass.ToInt32Static(s); // LINE B

Console.WriteLine(j);

Console.ReadLine();

}

}

为编译如上代码,你需要安装Visual Studio 2005和LINQ的预览版。如果你已经安装了VS2005,那么你将在Visual C#的LINQ Preview里看到三个新的工程模板:LINQ命令行应用程序,LINQ窗口程序和LINQ库。如下操作编译代码:

1. 打开VS2005编辑器,创建一个新工程,在新建工程窗口中选择LINQ Console作为工程模板。

2. 将工程命名为ExtensionMethods,点击Ok。

3. 将如上代码键入编辑器。

4. 按下F5编译工程并运行。

如果你只是安装了.NET 2.0,那么你可以运行命令行编译器:

Csc.exe /reference:"C:\Program Files\LINQ Preview\Bin

\System.Data.DLINQ.dll"

/reference:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.dll

/reference:"C:\Program Files\LINQ Preview\Bin\System.Query.dll"

/reference:"C:\Program Files\LINQ Preview\Bin\System.Xml.XLINQ.dll"

/target:exe Program.cs

就像你在如上代码里所看到的那样,扩展方法(ToInt32Ext)和普通的静态方法(ToInt32Static)的不同在于:

1. 扩展方法的第一个参数有一个this关键字,而静态方法不会在它的参数声明里有this关键字。

2. 当使用扩展方法的是哦户,使用this关键字声明的的参数没有进行传递。在上面的例子里,Line A就是一个使用扩展方法ToInt32Ext的例子。不需要将参数传递给它。当静态方法在使用的时候,是不能忽略掉任何的参数的。所有的参数必须传递进入函数。Line B就是一个例子。

3. 扩展方法只能在静态类中定义。对于静态方法,这并不成为一个要求,因为静态方法可以在一个静态类或普通类中存在。

4. 扩展方法只能针对实例调用。

扩展方法,尽管本质上还是静态的,但是只能针对实例调用。如果在一个类中调用它们将会引发编译错误。调用它们的类实例是由声明中的第一个参数决定的,就是有关键字this修饰的那个。

在IL内部

如果你观看IL里对以上代码的分析结果,你将会看到如下图的结果:

以下是IL对于扩展方法ToInt32Ext的分析:

.method public hidebysig static int32 ToInt32Ext(string s) cil managed

{

.custom instance void [System.Query]System.Runtime

.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )

// Code size 12 (0xc)

.maxstack 1

.locals init ([0] int32 CSCODE_REPLACEMENT 200)

IL_0000: nop

IL_0001: ldarg.0

IL_0002: call int32 [mscorlib]System.Int32::Parse(string)

IL_0007: stloc.0

IL_0008: br.s IL_000a

IL_000a: ldloc.0

IL_000b: ret

} // end of method EMClass::ToInt32Ext

以下代码是IL对静态方法ToInt32Static的分析:

.method public hidebysig static int32 ToInt32Static(string s) cil managed

{

// Code size 12 (0xc)

.maxstack 1

.locals init ([0] int32 CSCODE_REPLACEMENT 300)

IL_0000: nop

IL_0001: ldarg.0

IL_0002: call int32 [mscorlib]System.Int32::Parse(string)

IL_0007: stloc.0

IL_0008: br.s IL_000a

IL_000a: ldloc.0

IL_000b: ret

} // end of method EMClass::ToInt32Static

.custom instance void: 本行代码说明本方法只能针对实例使用。

[System.Query]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 ):本行代码说明扩展特性被使用了。

扩展方法转换

下表显示了在编译时进行的方法转换

方法

代码编译为

1

expr . identifier ( )

identifier (expr)

2

expr . identifier ( args )

identifier (expr, args)

3

expr . identifier <typeargs> ( )

identifier <typeargs> (expr)

4

expr . identifier <typeargs> ( args )

identifier <typeargs> (expr, args)

如果你在ILDASM中检查main方法的代码,它将会如下显示:

.method private hidebysig static void Main(string[] args) cil managed

{

.entrypoint

// Code size 42 (0x2a)

.maxstack 1

.locals init ([0] string s,

[1] int32 i,

[2] int32 j)

IL_0000: nop

IL_0001: ldstr "9"

IL_0006: stloc.0

IL_0007: ldloc.0

IL_0008: call int32 ExtensionMethods.EMClass::ToInt32Ext(string)

IL_000d: stloc.1

IL_000e: ldloc.1

IL_000f: call void [mscorlib]System.Console::WriteLine(int32)

IL_0014: nop

IL_0015: ldloc.0

IL_0016: call int32 ExtensionMethods.EMClass::

ToInt32Static(string)

IL_001b: stloc.2

IL_001c: ldloc.2

IL_001d: call void [mscorlib]System.Console::WriteLine(int32)

IL_0022: nop

IL_0023: call string [mscorlib]System.Console::ReadLine()

IL_0028: pop

IL_0029: ret

} // end of method Program::Main

IL_0008: call int32 ExtensionMethods.EMClass::

ToInt32Ext(string)

这里表明方法转换(expr . identifier ( ) <--> identifier (expr) )发生.

所以当你调用 int i = s.ToInt32Ext();, 编译器内部进行操作int i = EMClass.ToInt32Ext(s);那么,重写的新生会当作一个静态方法调用来处理

标识符按照如下的顺序解析:

1. 最近的包含的命名空间声明

2. 每个后继包含的命名空间声明

3. 包含的编译单元

下面是方法的从高到低的优先级:

1. 实例方法

2. 在同一个命名空间里的扩展方法

3. 在当前命名空间之外的扩展方法

为什么使用扩展方法?

你也许会问:"为什么有了普通的静态和实例类还需要使用扩展方法呢?"其实,简单来说就是为了方便。我来举个例子吧。如果你在过去的一段时间内开发了很多函数形成了一个库。那么当某人要用这个函数库的时候,他必须要知道定义了所需的静态方法的类名。就像下面这个一样:

a = MyLibraryClass.

这里,IntelliSense将会弹出并且告诉你可用函数的名字,你只需要挑选你所需要的。然后键入你需要的方法名和相关参数。

a = MyLibraryClass.DesiredFunction(strName)

使用这种方法,你必须事先知道哪个库包含了你所要的哪个函数和它的名称,使用扩展方法就不一样了:

a = strName.

这里,IntelliSense将会弹出,并且显示可以使用哪些扩展方法。你只需要键入你需要的扩展方法:

a = strName.DesiredFunction()

这里无须给出所需的参数名来指定数据类型。

在对象实例中调用静态方法

扩展方法提供了一个新的机制用来在对象实例上调用静态方法。但和实例方法比较起来,它还是在功能上有诸多限制,因此你应该保守的使用它,主要将它哦能够在实例方法能力所不及的地方。

C# 3.0并不是一个正式的版本,所以它的标准也没有最后定稿。因此,这样的格式也很有可能变化。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有