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

简介:
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并不是一个正式的版本,所以它的标准也没有最后定稿。因此,这样的格式也很有可能变化。
















本文转自朱先忠老师51CTO博客,原文链接:http://blog.51cto.com/zhuxianzhong/59326  ,如需转载请自行联系原作者




相关文章
|
7月前
|
C#
C#学习相关系列之数据类型类的三大特性(二)
C#学习相关系列之数据类型类的三大特性(二)
|
7月前
|
编译器 C# 开发者
C# 11.0中的新特性:覆盖默认接口方法
C# 11.0进一步增强了接口的灵活性,引入了覆盖默认接口方法的能力。这一新特性允许类在实现接口时,不仅可以提供接口中未实现的方法的具体实现,还可以覆盖接口中定义的默认方法实现。本文将详细介绍C# 11.0中接口默认方法覆盖的工作原理、使用场景及其对现有代码的影响,帮助开发者更好地理解和应用这一新功能。
|
7月前
|
编译器 C# 开发者
C# 9.0中的顶级语句:简化程序入口的新特性
【1月更文挑战第13天】本文介绍了C# 9.0中引入的顶级语句(Top-level statements)特性,该特性允许开发者在不使用传统的类和方法结构的情况下编写简洁的程序入口代码。文章详细阐述了顶级语句的语法、使用场景以及与传统程序结构的区别,并通过示例代码展示了其在实际应用中的便捷性。
|
1月前
|
编译器 C# 开发者
C# 9.0 新特性解析
C# 9.0 是微软在2020年11月随.NET 5.0发布的重大更新,带来了一系列新特性和改进,如记录类型、初始化器增强、顶级语句、模式匹配增强、目标类型的新表达式、属性模式和空值处理操作符等,旨在提升开发效率和代码可读性。本文将详细介绍这些新特性,并提供代码示例和常见问题解答。
49 7
C# 9.0 新特性解析
|
1月前
|
C# 开发者
C# 10.0 新特性解析
C# 10.0 在性能、可读性和开发效率方面进行了多项增强。本文介绍了文件范围的命名空间、记录结构体、只读结构体、局部函数的递归优化、改进的模式匹配和 lambda 表达式等新特性,并通过代码示例帮助理解这些特性。
36 2
|
3月前
|
编译器 C# Android开发
震惊!Uno Platform 与 C# 最新特性的完美融合,你不可不知的跨平台开发秘籍!
Uno Platform 是一个强大的跨平台应用开发框架,支持 Windows、macOS、iOS、Android 和 WebAssembly,采用 C# 和 XAML 进行编程。C# 作为其核心语言,持续推出新特性,如可空引用类型、异步流、记录类型和顶级语句等,极大地提升了开发效率。要在 Uno Platform 中使用最新 C# 特性,需确保开发环境支持相应版本,并正确配置编译器选项。通过示例展示了如何在 Uno Platform 中应用可空引用类型、异步流、记录类型及顶级语句等功能,帮助开发者更好地构建高效、优质的跨平台应用。
238 59
|
2月前
|
JSON C# 开发者
C#语言新特性深度剖析:提升你的.NET开发效率
【10月更文挑战第15天】C#语言凭借其强大的功能和易用性深受开发者喜爱。随着.NET平台的演进,C#不断引入新特性,如C# 7.0的模式匹配和C# 8.0的异步流,显著提升了开发效率和代码可维护性。本文将深入探讨这些新特性,助力开发者在.NET开发中更高效地利用它们。
44 1
|
4月前
|
开发框架 .NET 编译器
总结一下 C# 如何自定义特性 Attribute 并进行应用
总结一下 C# 如何自定义特性 Attribute 并进行应用
125 1
|
4月前
|
C# 索引
C#各大版本特性
C#各大版本特性
79 0
|
6月前
|
算法 C#
C#开源实用的工具类库,集成超过1000多种扩展方法
C#开源实用的工具类库,集成超过1000多种扩展方法