C#3.5语言新特性(四)-扩展方法


 

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

 

最常见的扩展方法是 LINQ 标准查询运算符,它们向现有的 System.Collections.IEnumerable 和 System.Collections.Generic.IEnumerable(T) 类型添加了查询功能。若要使用标准查询运算符,请首先通过 using System.Linq 指令将它们放到相应的范围中。然后,任何实现了 IEnumerable(T) 的类型看起来都具有 GroupBy、OrderBy、Average 等实例方法。在 IEnumerable(T) 类型的实例(如 List(T) 或 Array)后键入“点”时,可以在 IntelliSense 语句结束中看到这些附加方法。

 

下面的示例演示如何对一个整数数组调用标准查询运算符 OrderBy 方法。括号里面的表达式是一个 lambda 表达式。很多标准查询运算符采用 lambda 表达式作为参数,但这不是扩展方法的必要条件。

 

class ExtensionMethods2    

{



    static void Main()

    {            

        int[] ints = { 10, 45, 15, 39, 21, 26 };

        var result = ints.OrderBy(g => g);

        foreach (var i in result)

        {

            System.Console.Write(i + " ");

        }           

    }        

}

//Output: 10 15 21 26 39 45
 
在编译时绑定扩展方法
 
可以使用扩展方法来扩展类或接口,但不能重写扩展方法。与接口或类方法具有相同名称和签名的扩展方法永远不会被调用。编译时,扩展方法的优先级总是比类型本身中定义的实例方法低。换句话说,如果某个类型具有一个名为 Process(int i) 的方法,而您有一个具有相同签名的扩展方法,则编译器总是绑定到该实例方法。当编译器遇到方法调用时,它首先在该类型的实例方法中寻找匹配的方法。如果未找到任何匹配方法,编译器将搜索为该类型定义的任何扩展方法,并且绑定到它找到的第一个扩展方法
namespace Extensions

{

  using System;

  using ExtensionMethodsDemo1;



     // Define extension methods for any type that implements IMyInterface.

     public static class Extension

     {

        public static void MethodA(this IMyInterface myInterface, int i)

        {

            Console.WriteLine("Extension.MethodA(this IMyInterface myInterface, int i)");

        }



        public static void MethodA(this IMyInterface myInterface, string s) 

        {

            Console.WriteLine("Extension.MethodA(this IMyInterface myInterface, string s)");

        }



        // This method is never called, because the three classes implement MethodB.

        public static void MethodB(this IMyInterface myInterface) 

        {

            Console.WriteLine("Extension.MethodB(this IMyInterface myInterface)");

        }

    }

}

namespace ExtensionMethodsDemo1

{

    using System;

    using Extensions;



    public interface IMyInterface

    {

        void MethodB();

    }



    class A : IMyInterface 

    {

        public void MethodB(){Console.WriteLine("A.MethodB()");}

    } 



    class B : IMyInterface

    {

        public void MethodB() { Console.WriteLine("B.MethodB()"); }

        public void MethodA(int i) { Console.WriteLine("B.MethodA(int i)"); }

    }



    class C : IMyInterface

    {

        public void MethodB() { Console.WriteLine("C.MethodB()"); }

        public void MethodA(object obj) { Console.WriteLine("C.MethodA(object obj)"); }

    }



    class ExtMethodDemo

    {

        static void Main(string[] args)

        {

            A a = new A();

            B b = new B();

            C c = new C();

            TestMethodBinding(a,b,c);

        }



        static void TestMethodBinding(A a, B b, C c)

        {

            // A has no methods, so each call resolves to 

            // the extension methods whose signatures match.

            a.MethodA(1);           // Extension.MethodA(object, int)

            a.MethodA("hello");     // Extension.MethodA(object, string)

            a.MethodB();            // A.MethodB()



            // B itself has a method with this signature.

            b.MethodA(1);           // B.MethodA(int)

            b.MethodB();            // B.MethodB()



            // B has no matching method, but Extension does.

            b.MethodA("hello");     // Extension.MethodA(object, string)



            // In each case C has a matching instance method.

            c.MethodA(1);           // C.MethodA(object)

            c.MethodA("hello");     // C.MethodA(object)

            c.MethodB();            // C.MethodB()

        }

    }

}

/* Output:

    Extension.MethodA(this IMyInterface myInterface, int i)

    Extension.MethodA(this IMyInterface myInterface, string s)

    A.MethodB()

    B.MethodA(int i)

    B.MethodB()

    Extension.MethodA(this IMyInterface myInterface, string s)

    C.MethodA(object obj)

    C.MethodA(object obj)

    C.MethodB()

 */
 
示例演示 C# 编译器在确定是将方法调用绑定到类型上的实例方法还是绑定到扩展方法时所遵循的规则。静态类 Extensions 包含为任何实现了 IMyInterface 的类型定义的扩展方法。类 ABC 都实现了该接口。
MethodB 方法永远不会被调用,因为它的名称和签名与这些类已经实现的方法完全匹配。
如果编译器找不到具有匹配签名的实例方法,它会绑定到匹配的扩展方法(如果存在这样的方法)。

  
  
 

感觉上,扩展方法和javascript中的prototype编程类似,是扩展现有类型的方法。但是

通常,建议您只在不得已的情况下才实现扩展方法,并谨慎地实现。只要有可能,必须扩展现有类型的客户端代码都应该通过创建从现有类型派生的新类型来达到这一目的。在使用扩展方法来扩展您无法更改其源代码的类型时,您需要承受该类型实现中的更改会导致扩展方法失效的风险。

如果您确实为给定类型实现了扩展方法,请记住以下两点:

  • 如果扩展方法与该类型中定义的方法具有相同的签名,则扩展方法永远不会被调用。
  • 扩展方法被在命名空间级别放入范围中。例如,如果您在同一个名为 Extensions 的命名空间中具有多个包含扩展方法的静态类,则这些扩展方法将全部由 using Extensions; 指令放入范围中。

类库的实施者不应使用扩展方法来避免创建程序集的新版本。如果您要向库中添加重要的新功能,并且您

拥有源代码,则应该遵循标准 .NET Framework 程序集版本控制准则

  
  

 

如何:实现和调用自定义扩展方法

可以为 .NET Framework 类库中的任何类型或您想要扩展的任何其他 .NET 类型实现您自己的扩展方法。客户端代码可通过以下方式使用您的扩展方法:添加对包含这些扩展方法的 DLL 的引用,并且添加一条 using 指令以指定在其中定义这些扩展方法的命名空间。

定义和调用扩展方法

  1. 定义一个静态类以包含扩展方法。 该类必须对客户端代码可见。
  2. 将该扩展方法实现为静态方法,并使其至少具有与包含类相同的可见性。
  3. 该方法的第一个参数指定方法所操作的类型;该参数必须以 this 修饰符开头。
  4. 在调用代码中,添加一条 using 指令以指定包含扩展方法类的命名空间。
  5. 按照与调用类型上的实例方法一样的方式调用扩展方法。 请注意,第一个参数不是由调用代码指定的,因为它表示正应用运算符的类型,并且编译器已经知道对象的类型。您只需通过 n 为这两个形参提供实参。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值