C# Note21: 扩展方法(Extension Method)及其应用
前言
今天在开会时提到的一个概念,入职3个多月多注重在项目中使用C#的编程知识,一直没有很认真地过一遍C#的全部语法,当我们新人被问及是否了解Extension Method时,一时之间竟不能很通俗准确地描述。所以下面做个笔记吧。在空闲的时候还是要多看看MSDN的文档以及C#高级编程,熟悉相关语法知识,做到知其然也知其所以然!
(1)扩展方法有什么用?
扩展方法使您能够向现有类型添加方法,而无需创建新的派生类型、重新编译或修改原始类型。扩展方法是一种特殊的静态方法,但它们被称为扩展类型的实例方法。对于用c#和Visual Basic编写的客户机代码,调用扩展方法和在类型中定义的方法之间没有明显的区别。
C# 3.0就引入了该新特性,扩展方法可以很大的增加你代码的优美度,扩展方法提供了扩展.NET Framewoke类的扩展途径。
编写扩展方法有以下要求:
- 扩展方法所在的类必须是全局的,不能是内部嵌套类。
- 扩展方法的类是静态类。
- 扩展方法是静态方法。
- 扩展方法的第一个参数的数据类型必须是要扩展类型。
- 扩展方法的第一个参数使用this关键字。
(2)如何应用扩展方法?
有的时候,由于某些原因我们不能修改类本身的代码,但又需要在该类中增加功能,此时可以使用扩展方法。而且对于不能使用继承的结构和密封类来说,只能使用扩展方法增加功能。
注:一般而言,在非必要时,通过从现有类型中派生新类型来进行扩展,即继承的方式。因为,当使用扩展方法来扩展无法更改源代码的类型时,可能存在这样的风险:在实现类型中发生更改会导致扩展方法中断!
- 在编译时绑定扩展方法
You can use extension methods to extend a class or interface, but not to override them.
An extension method with the same name and signature as an interface or class method will never be called.
At compile time, extension methods always have lower priority than instance methods defined in the type itself.
In other words, if a type has a method named Process(int i), and you have an extension method with the same signature, the compiler will always bind to the instance method.
When the compiler encounters a method invocation, it first looks for a match in the type's instance methods. If no match is found, it will search for any extension methods that are defined for the type, and bind to the first extension method that it finds.
--MSDN
上述说明了c#编译器在决定是否将方法调用绑定到类型上的实例方法或扩展方法时所遵循的规则:
-如果扩展方法具有与类型中定义的方法相同的签名,则永远不会调用它。(注:对相同名称不同参数类型的方法使用扩展方法是可以的。)
-当编译器无法找到带有匹配签名的实例方法时,它将绑定到匹配的扩展方法,如果存在的话。
示例:
// Define an interface named IMyInterface.
namespace DefineIMyInterface
{
using System; public interface 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.
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 in ExtensionMethodsDemo1, because each
// of the three classes A, B, and C implements a method named MethodB
// that has a matching signature.
public static void 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
{
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)
{
// 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()
*/
要启用特定类型的扩展方法,只需为定义方法的命名空间添加一个using指令。
另外,注意不能对原类型中private方法使用扩展方法,否则就破坏了设计的初衷!
C# Note21: 扩展方法(Extension Method)及其应用的更多相关文章
- [译文]c#扩展方法(Extension Method In C#)
原文链接: https://www.codeproject.com/Tips/709310/Extension-Method-In-Csharp 介绍 扩展方法是C# 3.0引入的新特性.扩展方法使你 ...
- [0] C# 扩展方法(Extension Method)
有时有这样的情况,有一个类,你不能修改它,但你又想对它扩展(添加一个方法),这个时候就可以用到扩展方法了.请看下面的例子: using System;using System.Collections. ...
- .NET 扩展方法(Extention Method)的要点
扩展方法Extention Method的主要介绍在:http://msdn.microsoft.com/zh-cn/library/bb383977(v=vs.100).aspx. 扩展方法的意义在 ...
- C#创建自己的扩展方法
C#可以创建自己的扩展方法Extension Method: 参考这篇<判断是否为空然后赋值>http://www.cnblogs.com/insus/p/8004097.html 里,前 ...
- 在jQuery定义自己的扩展方法函数
今早复习昨天的练习jQuery的DropDownList联动功能,如果想看回<jQuery实现DropDownList(MVC)>http://www.cnblogs.com/insus/ ...
- [C#] Extension Method 扩展方法
当我们引用第三方的DLL.或者Visual Studio自己的库的时候,或许会发现这样的一个情况,如果这个类型有一个XX的方法就好了.这时候我们可以用到扩展方法,是我们的代码更加灵活和高效. 这里我举 ...
- c#编程指南(五) 扩展方法(Extension Method)
C# 3.0就引入的新特性,扩展方法可以很大的增加你代码的优美度,扩展方法提供你扩展.NET Framewoke类的扩展途径,书写和规则也简单的要命. 编写扩展方法有下面几个要求: 第一:扩展方法所在 ...
- C# -- 扩展方法的应用(Extension Methods)
当你有下面这样一个需求的时候,扩展方法就会起到作用:在项目中,类A需要添加功能,我们想到的就是在类A中添加公共方法,这个显而易见肯定可以,但是由于某种原因,你不能修改类A本身的代码,但是确实又需要增加 ...
- Extension Methods(扩展方法)
在 OOPL 中,有静态方法.实例方法和虚方法,如下: public sealed class String { public static bool IsNullOrEmpty(st ...
随机推荐
- 真正的Maven经常使用命令
长期用Eclipse的Maven插件的小伙伴可能接触Maven的经常使用命令比較少.每次用每次翻文档. 假设让你脱离Eclipse怎么办,面试的时候考到了怎么办-- 假设你不想尴尬,请小朋友花点时间运 ...
- Error: client: etcd cluster is unavailable or misconfigured; error #0: dial tcp 127.0.0.1:4001: getsockopt: connection refused
配置docker网络flannel时,配置etcd的key的时候出现以下错误 Error: client: etcd cluster is unavailable or misconfigured; ...
- 【转】AJAX发送 PUT和DELETE请求注意事项
jax使用restful服务发送put 和 delete 请求时直接传参会出现问题 一,采用POST + _method:delete/put + filter 的方法ajax发送put 和 de ...
- 【转】Android中dip(dp)与px之间单位转换
Android中dip(dp)与px之间单位转换 dp这个单位可能对web开发的人比较陌生,因为一般都是使用px(像素)但是,现在在开始android应用和游戏后,基本上都转换成用dp作用为单位了,因 ...
- ASP.Net:Javascript 通过PageMethods 调用后端WebMethod方法 + 多线程数据处理 示例
ASP.Net:Javascript 通过PageMethods 调用后端WebMethod方法 + 多线程数据处理 示例 2012年04月27日 16:59:16 奋斗的小壁虎 阅读数:4500 ...
- windows下使用svn命令行
1.安装“Slik-Subversion-1.9.7-win32.zip”,将路径写入windows的path路径 2.在cmd下可以执行svn 3.应为tortoiseSVN的版本比1的版本低,导致 ...
- i春秋-百度杯十月场-vld
查看源码,有提示,index.php.txt , 进入得到文本. 不太看得懂,后来百度,大致就是,flag1=.......&flag2=......&flag3=...... , ...
- 原生js学习 选择dom
连bootstrap5 都抛弃jquery了,重新使用原生js来写,所以最近在学习原生js. 一.选择dom元素: id let sure=document.getElementById('sure' ...
- AI 积分图
积分图(Integral Image),可以用于快速计算矩形特征.积分图每个位置(x, y)的值,等于原图对应位置的左上角所有像素点的值之和.因为“积分”在离散情况下就是求和,所以这也是积分图的命名由 ...
- Codechef SUMCUBE Sum of Cubes 组合、三元环计数
传送门 好久没有做过图论题了-- 考虑\(k\)次方的组合意义,实际上,要求的所有方案中导出子图边数的\(k\)次方,等价于有顺序地选出其中\(k\)条边,计算它们在哪一些图中出现过,将所有方案计算出 ...