C#语法之扩展
扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用。这是msdn的描述。上面几句我看好多博客都是这样开头的。所以我也这样开头。
原本想着上一篇博客回顾了下泛型,将具体的模糊化,这个应该讲反射,将模糊的具体化,不过呢看了下反射东西不少,一晚上我也总结不完,还要留点时间打飞机呢。于是想了想就总结下扩展吧。
一、为什么要有扩展方法?
开头也说了,无需创建新的派生类型、重新编译或其他方式修改原始类型给现有类或接口添加方法。比如在没有扩展之前,会经常有一些helper工具类,例如处理字符串、时间的。有了扩展我们可以直接扩展字符串类或时间类就可以了,这样不用在实例化helper类就能直接处理。
二、扩展方法有什么特征?
扩展方法是静态方法,是类的一部分,但是实际上没有放在类的源代码中。
扩展方法所在的类也必须被声明为static
C#只支持扩展方法,不支持扩展属性、扩展事件等。
扩展方法的第一个参数是要扩展的类型,放在this关键字的后面,this后面的参数不属于方法的参数
在扩展方法中,可以访问扩展类型的所有公共方法和属性。
扩展方法扩展自哪个类型,就必须是此类型的变量来使用,其他类型无法使用
如果扩展方法和实例方法具有相同的签名,则优先调用实例方法
扩展自父类上的方法,可以被子类的对象直接使用
扩展自接口上的方法,可以被实现类的对象直接使用
扩展方法最终还是被编译器编译成:静态类.静态方法()
三、demo
上面几句基本总结把扩展总结完了,下面做一个demo来说明一下。
1.定义IAnimal接口 声明void Eat();方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ExtensionMethod
{
public interface IAnimal
{
void Eat();
}
}
2.定义Person类实现接口IAnimal实现void Eat();方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ExtensionMethod
{
public class Person:IAnimal
{
public void Eat()
{
Console.WriteLine("Person Eat");
}
}
}
3.定义扩展方法ExtensionMethod
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ExtensionMethod
{
public static class ExtensionMethod
{
public static void Eat(this IAnimal iAnimal)
{
Console.WriteLine("IAnimalExtension Eat");
}
public static void Sleep(this IAnimal iAnimal)
{
Console.WriteLine("IAnimalExtension Sleep");
}
public static void Eat(this Person person)
{
Console.WriteLine("PersonExtension Eat");
}
public static void Sleep(this Person person)
{
Console.WriteLine("PersonExtension Sleep");
}
} }
上面在ExtensionMethod类中定义了4个扩展方法,两个是对接口IAnimal的扩展,两个是对Person类的扩展。
4.实例化测试
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ExtensionMethod
{
class Program
{
static void Main(string[] args)
{
IAnimal p = new Person();
p.Eat();
p.Sleep();
Console.WriteLine("----------------这是底线------------------------");
Person p1 = new Person();
p1.Eat();
p1.Sleep();
Console.WriteLine("----------------这是底线------------------------"); ExtensionMethod.Eat(p);
ExtensionMethod.Sleep(p);
Console.WriteLine("----------------这是底线------------------------");
ExtensionMethod.Eat(p1);
ExtensionMethod.Sleep(p1);
Console.ReadLine();
}
}
}
上面Mian方法中,首先实例化了一个Person对象,赋值给IAnimal类型的变量,调用Eat()和Sleep()方法。然后又实例化了一个Person对象,这次赋值给Person类型的变量。
下面来看下运行结果是不是出乎意料:

p和p1我们可以对比着来分析,对于Eat()方法都是输出"Person Eat",如果扩展方法和实例方法具有相同的签名,则优先调用实例方法,这句话正好能解释为什么。但是对于Sleep()方法,我们可以看到使用IAnimal类型的变量调用的是接口的扩展方法,使用Person类型的变量调用的是Person类型的扩展方法。扩展方法扩展自哪个类型,就必须是此类型的变量来使用,其他类型无法使用,与这句虽然有点出入,但也是蛮符合的。我是这样理解的:对于同名方法,实例方法优先扩展方法,自身扩展方法优先父类方法。 也可能是因为子类覆盖了父类的扩展方法。
我们可以把Person对的扩展方法注释,然后看下运行结果。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ExtensionMethod
{
public static class ExtensionMethod
{
public static void Eat(this IAnimal iAnimal)
{
Console.WriteLine("IAnimalExtension Eat");
}
public static void Sleep(this IAnimal iAnimal)
{
Console.WriteLine("IAnimalExtension Sleep");
}
//public static void Eat(this Person person)
//{
// Console.WriteLine("PersonExtension Eat");
//}
//public static void Sleep(this Person person)
//{
// Console.WriteLine("PersonExtension Sleep");
//}
} }

从上面的结果可以看到,扩展自接口上的方法,可以被实现类的对象直接使用,其实扩展自父类上的方法,可以被子类的对象直接使用和接口类似
C#语法之扩展的更多相关文章
- Swift2.1 语法指南——扩展
原档:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programmi ...
- C#语法糖: 扩展方法(常用)
今天继续分享C#4.0语法糖的扩展方法,这个方法也是我本人比较喜欢的方法.大家先想想比如我们以前写的原始类型不能满足现在的需求,而需要在该类型中添加新的方法来实现时大家会怎么做.我先说一下我没有学习到 ...
- 学习php语法--数据库扩展(总结篇)
前 言 php php中的数据库扩展mysql语法--本篇学习都是通过使用数字天堂的HBuider开发环境,连接mysql数据.介绍php连接mysql数据库的代码与函数. 本篇学习主要有两 ...
- Objective-C语法之扩展(Extension)的使用
Objective-C 2.0增加了Class Extension用于解决两个问题: 可声明私有可读写的属性,而在类的声明中是同名的公开只读属性,从而来支持公开只读.私有可读写的属性 可声明私有方法: ...
- ExtJs4 笔记(2) ExtJs对js基本语法扩展支持
本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引用加载 ExtJs有庞大的类型库,很多类可能在当前的页面根本不会用到,我们可以引入动态加载的概念来即用即取.这 ...
- ExtJs对js基本语法扩展支持
ExtJs对js基本语法扩展支持 本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引用加载 ExtJs有庞大的类型库,很多类可能在当前的页面根本不会用到,我们可 ...
- [转载]ExtJs4 笔记(2) ExtJs对js基本语法扩展支持
作者:李盼(Lipan)出处:[Lipan] (http://www.cnblogs.com/lipan/) 本篇主要介绍一下ExtJs对JS基本语法的扩展支持,包括动态加载.类的封装等. 一.动态引 ...
- 一些Markdown扩展语法
相信很多人跟我一样,对Markdown是"一知半解",会打一点,知道一点,但是其实从没花哪怕一分钟了解过.其实除了标题粗体插入代码,Markdown还有很多有趣的基础语法和扩展语法 ...
- .NET 扩展方法(Extention Method)的要点
扩展方法Extention Method的主要介绍在:http://msdn.microsoft.com/zh-cn/library/bb383977(v=vs.100).aspx. 扩展方法的意义在 ...
随机推荐
- IE下 input 的父级标签被 disabled 之后引发的怪异行为
前段时间做了个网盘类的项目,意外发现了这个情况 IE下,将input的父级标签增加 disabled 属性之后,input 的行为变得怪异: 1.input 背景变灰,疑似也被disabled 了. ...
- asp.net MVC把Areas区域绑定成二级域名
先分析需求 在MVC项目中,我们如果有两个Areas.比如Test和DEMO.我们的访问地址应该是 http://localhost:8098/test http://localhost:8098/d ...
- ruby,gem,rails之间的关系
Q:ruby,gem,rails之间的关系? 简单点说:Ruby是一种脚本语言,Gem是基于Ruby的一些开发工具包,Rails也算是一组Gem,专门用来做网站的.不同的Gem可能会依赖不同的Ruby ...
- delete job definition
$badjobTake2 = Get-SPTimerJob -ID "job-service-instance-f2de35ab-bca3-4e53-b51a-98d3b06a6930&qu ...
- 面试题-选择题Python
一. 6.下列表达式中返回为True的是() A.3>2>2 false B.'abc'>'xyz' false C.0x56<56 86<56 false 0x ...
- Day 18 正则表达式.
一.字符 .匹配除换行符以外的任意字符. \w 匹配字母数字或者下划线. \s 匹配任意的空白符 \d 匹配数字 \n 匹配一个换行符 \t 匹配一个制表符 ^ 匹配字符串的开始. $ 匹配字符串的结 ...
- IDEA取消默认工作区间
- 使用泛型SwingWorker与EDT事件分发线程保持通讯
为什么要使用SwingWorker 在swing开发中,如果一个应用程序,执行一些任务,需要大量的时间来完成,比如下载一个大文件或执行一个复杂的数据库查询. 我们假设这些任务是由用户使用一个按钮触发的 ...
- linux,修改文件夹权限
chmod -R 777 dist/ chown windseek:staff dist/ 改变dist的权限到staff组里的windseek用户下 alias ll=`ls -al` ...
- leetcode-914-卡牌分组
题目描述: 给定一副牌,每张牌上都写着一个整数. 此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组: 每组都有 X 张牌. 组内所有的牌上都写着相同的整数. 仅当你可选的 ...