(转)c# 扩展方法
扩展方法能够向现有类型“添加”方法,而无需创建新的派生类型,重新编译或以其他方式修改原始类型。扩展方法必须是静态方法,可以像实例方法一样进行调用。且调用同名中实际定义的方法优先级要高于扩展方法。
先来看看在经常使用List类型中使用扩展方法的例子,首先看看List是如何定义的:
// 摘要:
// Represents a strongly typed list of objects that can be accessed by index.
// Provides methods to search, sort, and manipulate lists.To browse the .NET
// Framework source code for this type, see the Reference Source.
//
// 类型参数:
// T:
// The type of elements in the list.
[Serializable]
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))]
public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
// 摘要:
// Initializes a new instance of the System.Collections.Generic.List<T> class
// that is empty and has the default initial capacity.
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public List();
//
// 摘要:
// Initializes a new instance of the System.Collections.Generic.List<T> class
// that contains elements copied from the specified collection and has sufficient
// capacity to accommodate the number of elements copied.
//
// 参数:
// collection:
// The collection whose elements are copied to the new list.
//
// 异常:
// System.ArgumentNullException:
// collection is null.
public List(IEnumerable<T> collection);
……
}
在List的类型定义中我们并没有看到有定义Union方法的地方,但是当我们在调用的时候就会出现:
<span style="white-space:pre"> </span>/// <summary>
/// 通过集合使用
/// </summary>
/// <param name="needSearchList"></param>
/// <param name="areaid"></param>
/// <returns></returns>
public List<AreaLineInfoModel> UseSetSearchCollection(List<AreaLineInfoModel> needSearchList, int areaid)
{
if (needSearchList == null || !needSearchList.Any()) return null;
const int area15 = 15;
var area15List = new List<AreaLineInfoModel>();
const int area16 = 16;
var area16List = new List<AreaLineInfoModel>();
const int area17 = 17;
var area17List = new List<AreaLineInfoModel>();
needSearchList.ForEach(
m =>
{
if (m.AreaIdList.Contains(area15)) area15List.Add(m);
if (m.AreaIdList.Contains(area16)) area16List.Add(m);
if (m.AreaIdList.Contains(area17)) area17List.Add(m);
});
if (areaid == area15) return area15List.Union(area16List).Union(area17List).ToList();
if (areaid == area16) return area16List.Union(area15List).Union(area17List).ToList();
if (areaid == area17) return area17List.Union(area15List).Union(area16List).ToList();
return null;
}
其中的Union方法哪里来的呢?我们转到定义看一看:
namespace System.Linq
{
public static class Enumerable
{
……
public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) {
if (first == null) throw Error.ArgumentNull("first");
if (second == null) throw Error.ArgumentNull("second");
return UnionIterator<TSource>(first, second, null);
}
}
}
so,也就是说,List的一个实例里面可以调用Enumerable里面的Union方法,如果我们不知道有扩展方法这回事的时候,以通常的想法,通过继承关系来找Union方法,会发现,List并没有实现Union方法,而且在继承的接口中也没有定义Union方法。这就比较纳闷了,这不是违背了面向对象的三大基本原则么?此话后说,我们先来自己实现一个扩展方法:
public interface IFreshList<T>
{
}
public static class testjinni
{
public static IFreshList<TSource> Union<TSource>(this IFreshList<TSource> first, IFreshList<TSource> second)
{
return second;
}
}
public class MyList<T> : IFreshList<T>
{
}
public class use
{
public void meth()
{
var temiList=new MyList<int>();
var mdaidnnf = new MyList<int>();
temiList.Union(mdaidnnf);
}
}
这只是一个简单的例子,你可以做你自己的扩展方法。
所有对象都能使用扩展:
public static class ExtendExt
{
public static void FuncExt(this object obj)
{
int b = 0;
}
}
msdn是这样规定扩展方法的:“扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。 它们的第一个参数指定该方法作用于哪个
类型,并且该参数以 this 修饰符为前缀。”通俗的说就是,扩展方法跟静态类的名称无关,只需要在一个静态类里面定义一个静态方法,第一个参数必须this T开头,
这个T就是一个泛型类型了。
小结:
本质上来说: 扩展方法是破坏原来的层次结构,通过网络结构加快业务逻辑处理;
扩展方法不改变被扩展类的代码,不用重新编译、修改、派生被扩展类;
扩展方法不能访问被扩展类的私有成员;
扩展方法会被被扩展类的同名方法覆盖,所以实现扩展方法我们需要承担随时被覆盖的风险;
扩展方法看似实现了面向对象中扩展对修改说不的特性,但是也违背了面向对象的继承原则,被扩展类的派生类是不能继承扩展扩展方法的,从而又违背了面向对象的多态性。;
在我们稳定的引用同一个版本的类库,但是我们没有该类库的源代码,那么我们可以使用扩展方法;但是从项目的可扩展、可维护和版本控制方面来说,都不建议使用扩展方法进行类的扩展。
文章转载自:https://blog.csdn.net/qin_zhangyongheng/article/details/52469476
(转)c# 扩展方法的更多相关文章
- .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法
.NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法 0x00 为什么需要Map(MapWhen)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...
- .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类
.NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类 0x00 为什么要引入扩展方法 有的中间件功能比较简单,有的则比较复杂,并且依赖其它组件.除 ...
- 为IEnumerable<T>添加RemoveAll<IEnumerable<T>>扩展方法--高性能篇
最近写代码,遇到一个问题,微软基于List<T>自带的方法是public bool Remove(T item);,可是有时候我们可能会用到诸如RemoveAll<IEnumerab ...
- C#的扩展方法解析
在使用面向对象的语言进行项目开发的过程中,较多的会使用到“继承”的特性,但是并非所有的场景都适合使用“继承”特性,在设计模式的一些基本原则中也有较多的提到. 继承的有关特性的使用所带来的问题:对象的继 ...
- 扩展方法(C#)
扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型.扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用. 下面的示例为String添加 ...
- 扩展方法解决LinqToSql Contains超过2100行报错问题
1.扩展方法 using System; using System.Collections.Generic; using System.Linq; using System.Web; using Sy ...
- C#扩展方法
扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法就相当于一个马甲,给一个现有类套上,就可以为这个类添加其他方法了. 马甲必须定义为stati ...
- 枚举扩展方法获取枚举Description
枚举扩展方法 /// <summary> /// 扩展方法,获得枚举的Description /// </summary> /// <param name="v ...
- 扩展方法 1 简单的string扩展方法
这里是关于 String的简单扩展方法 (静态类 静态方法 this 类型 这里是string) static class Program { static void Main(string[] ar ...
- C#中的扩展方法
扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用. 以上是msdn官网对扩展方 ...
随机推荐
- 数据结构(C语言)—排序
数据结构(C语言)—排序 排序 排序是按关键字的非递增或递减顺序对一组记录中心进行排序的操作.(将一组杂乱无章的数据按一定规律顺次排列起来.) 未定列表与不稳定列表 假设 Ki = Kj ( 1 ≤ ...
- 记一次gitlab添加用户收不到邮件的解决办法
之前再gitlab服务器上创建账号可以正常收到邮件,最近就收不到,查了gitlab的配置以及postfix服务都没有问题,后来查看了发信25端口,发现该25端口并没有开启(postfix已经开启),提 ...
- bzoj 2527 Meteors - 整体二分 - 树状数组
Description Byteotian Interstellar Union (BIU) has recently discovered a new planet in a nearby gala ...
- C++的STL之map自动排序特性
#include <iostream> #include <map> using namespace std; int main() {方法一: map<int,int& ...
- 使用Navicat for MySQL添加外键约束
转载:http://blog.csdn.net/u013215018/article/details/54981216 现在有两个表一张是Roles表(角色表),一张是RoleUser表(用户角色) ...
- HDU 6191 Query on A Tree(可持久化Trie)
题意 \(n\) 个点的有根树,根为 \(1\) .每个点有点权,有 \(q\) 个询问,每次询问以 \(u\) 为根的子树的点的点权中异或 \(x\) 所得的最大值是多少. 思路 求出整棵树的 \( ...
- @PathVariable与@RequestBody的区别,及前段请求接口的写法。
@PathVariable 1:接受参数时,地址栏为:/{args1}/{args2} 2:用法:(@PathVariable(value = "args")Long id) 3 ...
- facebook api之Business Manager API
Business-scoped Users - The new user is tied to a particular business and has permissions scoped to ...
- 测试常用的Linux命令总结
列出常用的命令和最常用的用法,排名不分先后:) 1. find在/home目录下查找以.txt结尾的文件名find /home -name "*.txt"同上,但忽略大小写find ...
- node.js 学习笔记一
2017-05-01 安装node 我没安装,下载即使用.要全局使用的话把node加入到环境变量中即可. 以下命令环境均为 cmd . 体验 体验一: 在命令行输入 node ,即进入 node 程序 ...