当前位置: 首页 > 编程语言 > C# > 正文

C#3.0扩展方法(Extension Methods)

时间:2007-09-27

今天早上在MSDN站点看到这样一篇文章: C# 3.0 LINQ 的演变及其对 C# 设计的影响 。 从这篇文章我们就可以明显的看到,C# 3.0 所新增的这些特性,可以认为都是为了LINQ 的发展,为了LINQ更易用,所创建的一些新特性,当然这些新特性也可以被非LINQ相关功能所使用。LINQ的发展,带动了C#3.0 这一系列新特性的产生。

回来说我们的话题,扩展方法,首先看一个最简单的代码例子:

扩展方法的定义,需要注意三个部分:1、静态类(私有公共都可以);2、静态方法(私有公共都可以);3、第一个函数参数前带 this(必须是第一参数前)

namespace Hongjun.Guo
{
static class MyExtensionMethods
{
internal static void Print(this object s)
{
Console.WriteLine(s);
}
}
}

扩展方法的使用,需要注意点: using 你定义所在的命名空间。
using Hongjun.Guo;
static void Main(string[] args)
{
object o = "dsdgs";
o.Print();
}

这样一个简简单单的代码后,我们就可以很方便的对一些不开源的第三方控件增加很多我们自己额外需要的功能。

扩展方法的使用,有时候并不是这么简简单单,我们来看一些特殊情况,通过这些特殊情况的分析,我们可以更深入的了解扩展方法:

情况一 : 扩展方法跟原来类的方法重名时候的处理逻辑。
场景:我们是对一个第三方的没有开放源代码组件的一个类扩展了一个方法,比如方法: Print 。过了一段时间后,这个第三方的组件发布了新版本,该类的增加了 Print 方法。这时候会出何种效果??
问题演示代码:
namespace Hongjun.Guo
{ public class MyClass
{
public void Print()
{
Console.WriteLine("****");
}
} static class MyExtensionMethods
{
internal static void Print(this MyClass s)
{
Console.WriteLine("haha " + s.ToString());
} }
}
调用范例:
using Hongjun.Guo;
static void Main(string[] args)
{
MyClass o = new MyClass();
o.Print(); Console.ReadLine();
}

这时候我们会看到何种结果呢??

答案:看到的是 **** 也就是,扩展方法跟类的方法冲突时候,编译使用不会报任何错误,这时候以类的方法优先级最高,这时我们使用类的方法,而不是扩展方法。 分析: 我们把上述两组代码编译后,再反编译成IL,我们就可以看到,实际上,扩展方法在IL层上是不存在的。 扩展方法实际是编译器调用某个类的某个方法的时候,先去这个类找,如果有这个方法,则就调用;如果找不到,根据引用的命名空间,再去找扩展方法(静态类的静态方法)。找到,就使用,找不到当然就编译错误了。 根据这个分析结果,我们就可以理解上述问题处理的结果了。

情况二: 扩展方法的嵌套 比如我们有如下扩展方法。

namespace Hongjun.Guo
{
static class MyExtensionMethods
{
public static int Test01(this int i)
{
return i * 3;
} public static int Test02(this int i)
{
return i + 5;
}
}
}

下面是调用范例:

static void Main(string[] args)
{
int mm = 7;
Console.WriteLine(mm.Test01().Test02());
Console.WriteLine("*****");
Console.WriteLine(mm.Test02().Test01()); Console.WriteLine("*****");
Console.WriteLine(MyExtensionMethods.Test02(MyExtensionMethods.Test01(mm)));

Console.ReadLine();
}
问,调用的显示结果是何值?
答案: 依次显示: 26,36,26
分析: mm.Test01().Test02() 这行代码编译后相当于如下代码: MyExtensionMethods.Test02(MyExtensionMethods.Test01(mm)) 这两行代码在编译后的IL中是完全一样的。