zoukankan      html  css  js  c++  java
  • C#3.0扩展方法学习篇

     什么是类的扩展方法

    扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。

    MSDN

    Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type.

    传统的模式下如果想为一个类型(class)添加一个额外的自定义的特殊的逻辑上,或者业务上的新方法时,你必须重新定义的一个类型来继承原有的的方法,用继承类或者接口,但是有些用sealed修饰的,这时候就无法被继承,例如String,值类型,sealed修饰的类。

    扩展方法是C#3.0这个版本提出来的。解决了必须由继承才能扩展的某个类的弊端,最重要的一点就是很好用。

    平时在我们使用的过程中也经常的见到,如
    这其中的OrderBy方法就是扩展方法。
    MSDN

    注意:

    扩展方法必须在非嵌套、非泛型的静态类中定义。

    Note that it is defined inside a non-nested<非嵌套>, non-generic<非泛型的> static<静态> class:

    扩展方法的规则有以下几点:

    • 扩展方法必须是扩展方法必须是非嵌套、非泛型的静态类中定义的;
    • 扩展方法的第一个参数要用this关键字修饰;
    • 第一个方法参数不能有ref 或则out关键字修饰的参数;
    扩展方法的调用有两个步骤
    1. 引用项目的命名空间;
    2. 参数调用两种;
    • 和传统的调用方法一样使用<ExtendClass>.<ExtendClassMethod>(参数,参数+?)
    • <参数类型>.<ExtendClassMethod>(参数+?)
    高级点的应用
        在编译时绑定扩展方法<MSDN>
        你可以使用扩展方法来扩展一个类和接口,而不需要去重写他们
      1 // Define an interface named IMyInterface.
      2 namespace DefineIMyInterface
      3 {
      4     using System;
      5 
      6     publicinterface IMyInterface
      7     {
      8         // Any class that implements IMyInterface must define a method
      9         // that matches the following signature.
     10         void MethodB();
     11     }
     12 }
     13 
     14 
     15 // Define extension methods for IMyInterface.
     16 namespace Extensions
     17 {
     18     using System;
     19     using DefineIMyInterface;
     20 
     21     // The following extension methods can be accessed by instances of any 
     22     // class that implements IMyInterface.
     23     publicstaticclass Extension
     24     {
     25         publicstaticvoid MethodA(this IMyInterface myInterface, int i)
     26         {
     27             Console.WriteLine
     28                 ("Extension.MethodA(this IMyInterface myInterface, int i)");
     29         }
     30 
     31         publicstaticvoid MethodA(this IMyInterface myInterface, string s)
     32         {
     33             Console.WriteLine
     34                 ("Extension.MethodA(this IMyInterface myInterface, string s)");
     35         }
     36 
     37         // This method is never called in ExtensionMethodsDemo1, because each 
     38         // of the three classes A, B, and C implements a method named MethodB
     39         // that has a matching signature.
     40         publicstaticvoid MethodB(this IMyInterface myInterface)
     41         {
     42             Console.WriteLine
     43                 ("Extension.MethodB(this IMyInterface myInterface)");
     44         }
     45     }
     46 }
     47 
     48 
     49 // Define three classes that implement IMyInterface, and then use them to test
     50 // the extension methods.
     51 namespace ExtensionMethodsDemo1
     52 {
     53     using System;
     54     using Extensions;
     55     using DefineIMyInterface;
     56 
     57     class A : IMyInterface
     58     {
     59         publicvoid MethodB() { Console.WriteLine("A.MethodB()"); }
     60     }
     61 
     62     class B : IMyInterface
     63     {
     64         publicvoid MethodB() { Console.WriteLine("B.MethodB()"); }
     65         publicvoid MethodA(int i) { Console.WriteLine("B.MethodA(int i)"); }
     66     }
     67 
     68     class C : IMyInterface
     69     {
     70         publicvoid MethodB() { Console.WriteLine("C.MethodB()"); }
     71         publicvoid MethodA(object obj)
     72         {
     73             Console.WriteLine("C.MethodA(object obj)");
     74         }
     75     }
     76 
     77     class ExtMethodDemo
     78     {
     79         staticvoid Main(string[] args)
     80         {
     81             // Declare an instance of class A, class B, and class C.
     82             A a = new A();
     83             B b = new B();
     84             C c = new C();
     85 
     86             // For a, b, and c, call the following methods://      -- MethodA with an int argument//      -- MethodA with a string argument//      -- MethodB with no argument.// A contains no MethodA, so each call to MethodA resolves to // the extension method that has a matching signature.
     87             a.MethodA(1);           // Extension.MethodA(object, int)
     88             a.MethodA("hello");     // Extension.MethodA(object, string)// A has a method that matches the signature of the following call// to MethodB.
     89             a.MethodB();            // A.MethodB()// B has methods that match the signatures of the following// method calls.
     90             b.MethodA(1);           // B.MethodA(int)
     91             b.MethodB();            // B.MethodB()// B has no matching method for the following call, but // class Extension does.
     92             b.MethodA("hello");     // Extension.MethodA(object, string)// C contains an instance method that matches each of the following// method calls.
     93             c.MethodA(1);           // C.MethodA(object)
     94             c.MethodA("hello");     // C.MethodA(object)
     95             c.MethodB();            // C.MethodB()
     96         }
     97     }
     98 }
     99 /* Output:
    100     Extension.MethodA(this IMyInterface myInterface, int i)
    101     Extension.MethodA(this IMyInterface myInterface, string s)
    102     A.MethodB()
    103     B.MethodA(int i)
    104     B.MethodB()
    105     Extension.MethodA(this IMyInterface myInterface, string s)
    106     C.MethodA(object obj)
    107     C.MethodA(object obj)
    108     C.MethodB()
    109  */
    编译器是如何发现扩展方法的
    c# 3.0编译器看到某个类的调用用法时,先是从该类的实例方法中进行查找,如果没有找到与调用方法同名并参数一致的实例方法,再从所有导入的命名空间中查找是否有合适的扩展方法,并将变量类型匹配到扩展类型。
    这只是我们的理解是这样一个过程,如果在同一个命名空间下,编译器则会直接用当前命名空间下符合条件的对应方法,让我看下下ILDasm.exe.
    如果不是同一个程序集的命名空间可以在MANIFEST清单文件里看出。

    总结的结果

    方法的调用次序 类型的实例方法--->当前命名空间下的扩展方法--->导入的其他命名空间扩展方法。

    引发疑问

    在空引用上调用实例方法或静态方法时会抛出NullReferenceException异常?那么在类调用扩展方法时会出现异常吗?(不使用类中的一些属性或方法,强调调用)

            public static void NullUse(this TestExtend sextend)
            {
                Console.WriteLine("NUll used Method");
            }
    分析:在空的类型上定义扩展方法不出现NullReferenceException,只是把空这个引用当成参数传入静态方法,
    扩展方法 静态方法
    TestExtend sExtend=null;
                sExtend.NullUse();
    TestExtend sExtend=null;
    NullUse.(sExtend);
     
     
     
    从ILDASM能看出我们猜想的正确性
    Notice

    可能引发的子类污染的问题例如

            public static bool isNull(this object str)  
            {
                return str == null;
            }

    你本来只想扩展TestExtend 这个类的方法,由于你要使用iSNull这个类型的扩展结果传入参数(object),结果导致所有的object 类型都扩展了这个方法,这会带来可怕的后果。

    所以在扩展一个类型的方法时,要从确定类型扩展。尽量避免从父类去扩展。

    有什么不对的或者错误的地方希望大家给予指正,谢谢

    我的开发环境VS2015

    DEMO的下载  【http://pan.baidu.com/s/1bY51P8】

  • 相关阅读:
    显卡信息
    统一处理labelme标注的json文件名
    Qt窗口设置最大高度
    未定义av_image_get_buffer_size
    AVPixelFormat
    树结构系列开篇:聊聊如何学习树结构?
    PriorityQueue 是线性结构吗?90%的人都搞错了!
    硬核!史上最全的工厂模式文章,从零到一全面讲解!
    如何从分类层面,深入理解设计模式?
    程序员重构入门指南
  • 原文地址:https://www.cnblogs.com/knightlilz/p/5335562.html
Copyright © 2011-2022 走看看