首页 技术 正文
技术 2022年11月14日
0 收藏 411 点赞 4,342 浏览 4557 个字

 什么是类的扩展方法

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

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这个版本提出来的。解决了必须由继承才能扩展的某个类的弊端,最重要的一点就是很好用。

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

注意:

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

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

C#3.0扩展方法学习篇C#3.0扩展方法学习篇

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

  • 扩展方法必须是扩展方法必须是非嵌套、非泛型的静态类中定义的;
  • 扩展方法的第一个参数要用this关键字修饰;
  • 第一个方法参数不能有ref 或则out关键字修饰的参数;

扩展方法的调用有两个步骤

  1. 引用项目的命名空间;
  2. 参数调用两种;
  • 和传统的调用方法一样使用<ExtendClass>.<ExtendClassMethod>(参数,参数+?)
  • <参数类型>.<ExtendClassMethod>(参数+?)

高级点的应用    在编译时绑定扩展方法<MSDN>    你可以使用扩展方法来扩展一个类和接口,而不需要去重写他们

 // Define an interface named IMyInterface.
namespace DefineIMyInterface
{
using System; publicinterface IMyInterface
{
// Any class that implements IMyInterface must define a method
// that matches the following signature.
void MethodB();
}
} // Define extension methods for IMyInterface.
namespace Extensions
{
using System;
using DefineIMyInterface; // The following extension methods can be accessed by instances of any
// class that implements IMyInterface.
publicstaticclass Extension
{
publicstaticvoid MethodA(this IMyInterface myInterface, int i)
{
Console.WriteLine
("Extension.MethodA(this IMyInterface myInterface, int i)");
} publicstaticvoid MethodA(this IMyInterface myInterface, string s)
{
Console.WriteLine
("Extension.MethodA(this IMyInterface myInterface, string s)");
} // This method is never called in ExtensionMethodsDemo1, because each
// of the three classes A, B, and C implements a method named MethodB
// that has a matching signature.
publicstaticvoid MethodB(this IMyInterface myInterface)
{
Console.WriteLine
("Extension.MethodB(this IMyInterface myInterface)");
}
}
} // Define three classes that implement IMyInterface, and then use them to test
// the extension methods.
namespace ExtensionMethodsDemo1
{
using System;
using Extensions;
using DefineIMyInterface; class A : IMyInterface
{
publicvoid MethodB() { Console.WriteLine("A.MethodB()"); }
} class B : IMyInterface
{
publicvoid MethodB() { Console.WriteLine("B.MethodB()"); }
publicvoid MethodA(int i) { Console.WriteLine("B.MethodA(int i)"); }
} class C : IMyInterface
{
publicvoid MethodB() { Console.WriteLine("C.MethodB()"); }
publicvoid MethodA(object obj)
{
Console.WriteLine("C.MethodA(object obj)");
}
} class ExtMethodDemo
{
staticvoid Main(string[] args)
{
// Declare an instance of class A, class B, and class C.
A a = new A();
B b = new B();
C c = new C(); // 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.
a.MethodA(); // Extension.MethodA(object, int)
a.MethodA("hello"); // Extension.MethodA(object, string)// A has a method that matches the signature of the following call// to MethodB.
a.MethodB(); // A.MethodB()// B has methods that match the signatures of the following// method calls.
b.MethodA(); // B.MethodA(int)
b.MethodB(); // B.MethodB()// B has no matching method for the following call, but // class Extension does.
b.MethodA("hello"); // Extension.MethodA(object, string)// C contains an instance method that matches each of the following// method calls.
c.MethodA(); // 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# 3.0编译器看到某个类的调用用法时,先是从该类的实例方法中进行查找,如果没有找到与调用方法同名并参数一致的实例方法,再从所有导入的命名空间中查找是否有合适的扩展方法,并将变量类型匹配到扩展类型。这只是我们的理解是这样一个过程,如果在同一个命名空间下,编译器则会直接用当前命名空间下符合条件的对应方法,让我看下下ILDasm.exe.C#3.0扩展方法学习篇C#3.0扩展方法学习篇如果不是同一个程序集的命名空间可以在MANIFEST清单文件里看出。C#3.0扩展方法学习篇C#3.0扩展方法学习篇

总结的结果

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

引发疑问

在空引用上调用实例方法或静态方法时会抛出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能看出我们猜想的正确性C#3.0扩展方法学习篇C#3.0扩展方法学习篇Notice

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

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

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

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

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

我的开发环境VS2015

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

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,086
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,561
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,410
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,183
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,820
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,903