前言

今天在开会时提到的一个概念,入职3个多月多注重在项目中使用C#的编程知识,一直没有很认真地过一遍C#的全部语法,当我们新人被问及是否了解Extension Method时,一时之间竟不能很通俗准确地描述。所以下面做个笔记吧。在空闲的时候还是要多看看MSDN的文档以及C#高级编程,熟悉相关语法知识,做到知其然也知其所以然!

本篇可参考:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

(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)及其应用的更多相关文章

  1. [译文]c#扩展方法(Extension Method In C#)

    原文链接: https://www.codeproject.com/Tips/709310/Extension-Method-In-Csharp 介绍 扩展方法是C# 3.0引入的新特性.扩展方法使你 ...

  2. [0] C# 扩展方法(Extension Method)

    有时有这样的情况,有一个类,你不能修改它,但你又想对它扩展(添加一个方法),这个时候就可以用到扩展方法了.请看下面的例子: using System;using System.Collections. ...

  3. .NET 扩展方法(Extention Method)的要点

    扩展方法Extention Method的主要介绍在:http://msdn.microsoft.com/zh-cn/library/bb383977(v=vs.100).aspx. 扩展方法的意义在 ...

  4. C#创建自己的扩展方法

    C#可以创建自己的扩展方法Extension Method: 参考这篇<判断是否为空然后赋值>http://www.cnblogs.com/insus/p/8004097.html 里,前 ...

  5. 在jQuery定义自己的扩展方法函数

    今早复习昨天的练习jQuery的DropDownList联动功能,如果想看回<jQuery实现DropDownList(MVC)>http://www.cnblogs.com/insus/ ...

  6. [C#] Extension Method 扩展方法

    当我们引用第三方的DLL.或者Visual Studio自己的库的时候,或许会发现这样的一个情况,如果这个类型有一个XX的方法就好了.这时候我们可以用到扩展方法,是我们的代码更加灵活和高效. 这里我举 ...

  7. c#编程指南(五) 扩展方法(Extension Method)

    C# 3.0就引入的新特性,扩展方法可以很大的增加你代码的优美度,扩展方法提供你扩展.NET Framewoke类的扩展途径,书写和规则也简单的要命. 编写扩展方法有下面几个要求: 第一:扩展方法所在 ...

  8. C# -- 扩展方法的应用(Extension Methods)

    当你有下面这样一个需求的时候,扩展方法就会起到作用:在项目中,类A需要添加功能,我们想到的就是在类A中添加公共方法,这个显而易见肯定可以,但是由于某种原因,你不能修改类A本身的代码,但是确实又需要增加 ...

  9. Extension Methods(扩展方法)

    在 OOPL 中,有静态方法.实例方法和虚方法,如下:   public sealed class String {      public static bool  IsNullOrEmpty(st ...

随机推荐

  1. go 调用windows dll 的三种方法

    参考:https://blog.csdn.net/qq_39584315/article/details/81287669 大部分代码参考:https://studygolang.com/articl ...

  2. 匆忙记录 编译linux kernel zImage

    arm的板子. 自己要定制下内核. 下载源码 cp 模板配置 .config make menuconfig 进行定制化 之后make zImage {注意 交叉编译 gcc 也要配置的} 之后 ./ ...

  3. Python学习笔记(2)-字典

    什么是字典? 像列表一样,但是不能想列表用下表索引,而是通过'键',键及其关联的值称为'键-值'对.字典经常会简写成dict 创建字典{} 例如: >>> dict = {'one' ...

  4. 003_webpack 配合babel 将es6转成es5

    今天接触了webpack,第一次使用webpack进行转码,竟然稀里糊涂就成功了,哈哈. 下面附上流程 创建个文件夹,初始化一下,首先全局安装webpack npm install webpack - ...

  5. Consul在.Net Core中初体验

    Consul在.Net Core中初体验 简介 在阅读本文前我想您应该对微服务架构有一个基本的或者模糊的了解 Consul是一个服务管理软件,它其实有很多组件,包括服务发现配置共享键值对存储等 本文主 ...

  6. linux命令之 tar

    参数 -c 创建新归档 -d 比较归档和文件系统的差异 -r 追加文件到归档 -t 存档的内容列表 -x 提取归档所有文件 -C 改变解压目录 -f 使用归档文件或设备归档 -j bzip2 压缩 - ...

  7. Oracle 周相关函数

    Oracle 周相关函数   select trunc(sysdate,'W'), --每月1日作为第一个星期第一天 取当前周第一天对应日期 trunc(sysdate,'WW'), --每年1月1日 ...

  8. 用java语言写一个简易版本的登录页面,包含用户注册、用户登录、用户注销、修改密码等功能

    package com.Summer_0421.cn; import java.util.Arrays; import java.util.Scanner; /** * @author Summer ...

  9. BZOJ3309 DZY Loves Maths 莫比乌斯反演、线性筛

    传送门 推式子(默认\(N \leq M\)): \(\begin{align*} \sum\limits_{i=1}^N \sum\limits_{j=1}^Mf(gcd(i,j)) & = ...

  10. IntelliJ IDEA(四) :Settings(上)

    前言 IDEA是一个智能开发工具,每个开发者的使用习惯不同,如何个性化自己的IDEA?我们可以通过Settings功能来设置.Settings文件是IDEA的配置文件,通过他可以设置主题,项目,插件, ...