C#秘密武器之扩展方法
原文:C#秘密武器之扩展方法
为何要用扩展方法?
作为一个.NET程序猿,我们经常要跟.net自带类库或者第三方dll类库打交道,有时候我们未必能够通过反编译来查看它们的代码,但是我们通常需要给它们扩充一些新的功能,Helper类就应运而生了,我们开发出一个个的静态方法以方便调用。久而久之,我们封装的Helper类越来越多,但是这个Helper里边的方法不一定为每个开发人员所熟知,而且我们每每要敲击XXXHelper.XXX()这种类似的方法,其实这个XXXHelper完全是可以省略掉的,等于是我们每次都多写了这么一点东西。
有没有解决办法呢?扩展方法就是解决这个问题的。扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。它可以对现有类功能进行扩充,从而使该类型的实例具有更多的方法,伟大的LINQ就是用的这个东西实现的。
使用扩展方法的好处:
1、让方法调用回归面向对象本身,即方法是属于对象的,增强代码可读性
2、从一定程度上来说扩展方法让你的类库有了无限的可能性
扩展方法的应用
扩展方法必须遵守以下规则:
1.扩展类必须是静态非泛型的;
2.扩展方法必须是静态的
3.扩展方法的第一个参数必须以this开头,参数必须是原有类的类型
举个扩展方法的栗子:
我们经常需要对对象进行序列化,那么我们可以给对象object扩展一个这样的方法ToJSON
using Newtonsoft.Json;
namespace Ctrip.Json
{
public static class JsonHelper
{
public static string ToJson(this object obj)
{
string JsonStr = JsonConvert.SerializeObject(obj);
return JsonStr;
}
}
}
调用:
using Ctrip.Json;
Student stu=new Student{Name="张三",Sex="男",Age=};
string jsonString = stu.ToJson();
平时我们总是需要操作字符串类型,因此这里就送上一个string类型的扩展方法类库:
using System;
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using Infrastructure.Common;
using Newtonsoft.Json;
namespace Infrastructure.Utility
{
/// <summary>
/// 字符串类型帮助类
/// </summary>
public static class StringHelper
{
/// <summary>
/// Object对象序列化为Json字串
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string ToJson(this object obj)
{
return JsonConvert.SerializeObject(obj);
}
/// <summary>
/// Json字串反序列化为Object强类型
/// </summary>
public static T DeJson<T>(this string json)
{
return JsonConvert.DeserializeObject<T>(json);
}
/// <summary>
/// 根据根据字符串转换成相对应的枚举子项
/// </summary>
/// <typeparam name="TEnum">枚举类型</typeparam>
/// <param name="strEnumDescription">字符串</param>
/// <returns>枚举子项</returns>
public static TEnum ToEnum<TEnum>(this string strEnumDescription)
where TEnum : struct
{
Type enumType = typeof(TEnum);
TEnum[] enumValues = (TEnum[])Enum.GetValues(enumType);
foreach (var enumValue in enumValues)
{
string strValue = enumValue.ToString();
FieldInfo fieldinfo = enumValue.GetType().GetField(strValue);
object[] objs = fieldinfo.GetCustomAttributes(typeof(EnumItemAttribute), false);
if (objs.Length == )
{
continue;
}
EnumItemAttribute enumItemAttribute = (EnumItemAttribute)objs[];
if (enumItemAttribute != null && string.Equals(enumItemAttribute.Description, strEnumDescription, StringComparison.CurrentCultureIgnoreCase))
{
return enumValue;
}
}
return default(TEnum);
}
/// <summary>
/// 获得字符串的长度,一个汉字的长度为1
/// </summary>
public static int GetStringLength(string s)
{
if (!string.IsNullOrEmpty(s))
return Encoding.Default.GetBytes(s).Length;
return ;
}
/// <summary>
/// 获得字符串中指定字符的个数
/// </summary>
/// <param name="s">字符串</param>
/// <param name="c">字符</param>
/// <returns></returns>
public static int GetCharCount(string s, char c)
{
if (s == null || s.Length == )
return ;
int count = ;
foreach (char a in s)
{
if (a == c)
count++;
}
return count;
}
/// <summary>
/// 获得指定顺序的字符在字符串中的位置索引
/// </summary>
/// <param name="s">字符串</param>
/// <param name="order">顺序</param>
/// <returns></returns>
public static int IndexOf(string s, int order)
{
return IndexOf(s, '-', order);
}
/// <summary>
/// 获得指定顺序的字符在字符串中的位置索引
/// </summary>
/// <param name="s">字符串</param>
/// <param name="c">字符</param>
/// <param name="order">顺序</param>
/// <returns></returns>
public static int IndexOf(string s, char c, int order)
{
int length = s.Length;
for (int i = ; i < length; i++)
{
if (c == s[i])
{
if (order == )
return i;
order--;
}
}
return -;
}
#region 分割字符串
/// <summary>
/// 分割字符串
/// </summary>
/// <param name="sourceStr">源字符串</param>
/// <param name="splitStr">分隔字符串</param>
/// <returns></returns>
public static string[] SplitString(string sourceStr, string splitStr)
{
if (string.IsNullOrEmpty(sourceStr) || string.IsNullOrEmpty(splitStr))
return new string[] { };
if (sourceStr.IndexOf(splitStr) == -)
return new string[] { sourceStr };
if (splitStr.Length == )
return sourceStr.Split(splitStr[]);
else
return Regex.Split(sourceStr, Regex.Escape(splitStr), RegexOptions.IgnoreCase);
}
/// <summary>
/// 分割字符串
/// </summary>
/// <param name="sourceStr">源字符串</param>
/// <returns></returns>
public static string[] SplitString(string sourceStr)
{
return SplitString(sourceStr, ",");
}
#endregion
#region 截取字符串
/// <summary>
/// 截取字符串
/// </summary>
/// <param name="sourceStr">源字符串</param>
/// <param name="startIndex">开始位置的索引</param>
/// <param name="length">子字符串的长度</param>
/// <returns></returns>
public static string SubString(string sourceStr, int startIndex, int length)
{
if (!string.IsNullOrEmpty(sourceStr))
{
if (sourceStr.Length >= (startIndex + length))
return sourceStr.Substring(startIndex, length);
else
return sourceStr.Substring(startIndex);
}
return "";
}
/// <summary>
/// 截取字符串
/// </summary>
/// <param name="sourceStr">源字符串</param>
/// <param name="length">子字符串的长度</param>
/// <returns></returns>
public static string SubString(string sourceStr, int length)
{
return SubString(sourceStr, , length);
}
#endregion
#region 移除前导/后导字符串
/// <summary>
/// 移除前导字符串
/// </summary>
/// <param name="sourceStr">源字符串</param>
/// <param name="trimStr">移除字符串</param>
/// <returns></returns>
public static string TrimStart(string sourceStr, string trimStr)
{
return TrimStart(sourceStr, trimStr, true);
}
/// <summary>
/// 移除前导字符串
/// </summary>
/// <param name="sourceStr">源字符串</param>
/// <param name="trimStr">移除字符串</param>
/// <param name="ignoreCase">是否忽略大小写</param>
/// <returns></returns>
public static string TrimStart(string sourceStr, string trimStr, bool ignoreCase)
{
if (string.IsNullOrEmpty(sourceStr))
return string.Empty;
if (string.IsNullOrEmpty(trimStr) || !sourceStr.StartsWith(trimStr, ignoreCase, CultureInfo.CurrentCulture))
return sourceStr;
return sourceStr.Remove(, trimStr.Length);
}
/// <summary>
/// 移除后导字符串
/// </summary>
/// <param name="sourceStr">源字符串</param>
/// <param name="trimStr">移除字符串</param>
/// <returns></returns>
public static string TrimEnd(string sourceStr, string trimStr)
{
return TrimEnd(sourceStr, trimStr, true);
}
/// <summary>
/// 移除后导字符串
/// </summary>
/// <param name="sourceStr">源字符串</param>
/// <param name="trimStr">移除字符串</param>
/// <param name="ignoreCase">是否忽略大小写</param>
/// <returns></returns>
public static string TrimEnd(string sourceStr, string trimStr, bool ignoreCase)
{
if (string.IsNullOrEmpty(sourceStr))
return string.Empty;
if (string.IsNullOrEmpty(trimStr) || !sourceStr.EndsWith(trimStr, ignoreCase, CultureInfo.CurrentCulture))
return sourceStr;
return sourceStr.Substring(, sourceStr.Length - trimStr.Length);
}
/// <summary>
/// 移除前导和后导字符串
/// </summary>
/// <param name="sourceStr">源字符串</param>
/// <param name="trimStr">移除字符串</param>
/// <returns></returns>
public static string Trim(string sourceStr, string trimStr)
{
return Trim(sourceStr, trimStr, true);
}
/// <summary>
/// 移除前导和后导字符串
/// </summary>
/// <param name="sourceStr">源字符串</param>
/// <param name="trimStr">移除字符串</param>
/// <param name="ignoreCase">是否忽略大小写</param>
/// <returns></returns>
public static string Trim(string sourceStr, string trimStr, bool ignoreCase)
{
if (string.IsNullOrEmpty(sourceStr))
return string.Empty;
if (string.IsNullOrEmpty(trimStr))
return sourceStr;
if (sourceStr.StartsWith(trimStr, ignoreCase, CultureInfo.CurrentCulture))
sourceStr = sourceStr.Remove(, trimStr.Length);
if (sourceStr.EndsWith(trimStr, ignoreCase, CultureInfo.CurrentCulture))
sourceStr = sourceStr.Substring(, sourceStr.Length - trimStr.Length);
return sourceStr;
}
#endregion
}
}
备注:
1、在vs的智能提示中,扩展方法是带有蓝色下滑箭头的
2、如果扩展方法和被扩展类中的方法相同,会怎么样?
扩展方法的优先级总是比类型本身中定义的实例方法低,所以与接口或类方法具有相同名称和签名的扩展方法永远不会被调用。
3、注意你是为哪个类型进行扩展,比如你是对string类型做扩展,还是对object类型、List<object>类型做扩展,一定要明确扩展的类型范围
4、是时候尝试将你的那些Helper类库转换成扩展方法了
5、当你苦于类库里没有你想要的方法时,那就大胆的扩展吧
总结:
扩展方法本身并不难,难点在于你是否能够恰到好处地使用它,也就是说你是否知道在某个合适的时候使用它。
C#秘密武器之扩展方法的更多相关文章
- margin负值 – 一个秘密武器
CSS盒模型中,margin是我们老熟悉的一个属性了, 它的负值你用过吗? 你知道 margin负值的秘密武器吗?我们一起看看吧! 1.带竖线分隔的横向列表(例如:网站底部栏目) 传统的分隔符是使用 ...
- TypeScript: Angular 2 的秘密武器(译)
本文整理自Dan Wahlin在ng-conf上的talk.原视频地址: https://www.youtube.com/watch?v=e3djIqAGqZo 开场白 开场白主要分为三部分: 感谢了 ...
- 团队高效率协作开发的秘密武器-APIDOC
团队高效率协作开发的秘密武器 1.前言 在团队协作开发中,不知道各位有没有遇到这样的问题: l 新人接手了项目代码,因没有项目文档,只能靠追踪路由,寻读代码分析业务逻辑 l 前端同学写好了页面,苦等后 ...
- 当3D打影人头”成为黑客的秘密武器,隐私该如何保护?
在<碟中谍>系列电影中,除了超级敬业又帅气的阿汤哥之外,最让人津津乐道的桥段就是用3D打印做出来的"人头".通过这些惟妙惟肖的"人头",阿汤哥完成了 ...
- .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添加 ...
随机推荐
- 【转】Android 4.3源码下载及问题解决
[html] view plaincopy 1 2 3 4 5 6 7 8 9 10 11 jianguoliao@jianguoliao-Lenovo-IdeaPad-Y470:~$ cat /et ...
- OpenGL【2 坐标转换】
// OpenGL.cpp : 自定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include & ...
- 新建WindowsPhone项目时提示未将对象引用设置到对象的实例
问题: 安装好新系统之后(只有Windows8 专业版和企业版支持hyper-v),然后安装vs2012,再安装Wp8 Sdk,安装完毕后新建Windows Phone项目,会提示未将对象引用设置到对 ...
- SAP ABAP 它已被释放TR(或任务),减少的变化TR(任务),删除释放TR(任务)
有时,我们会遇到将是一个TR以下任务task发布,然后想改变,或不想转移TR. 或想删除已释放TR. 研究发现后面,TR(任务)存储在数据库表汇的相应数据:E070(变化 & 交通系统: 求/ ...
- MVC把随机产生的字符串转换为图片
原文:MVC把随机产生的字符串转换为图片 Insus.NET在这篇中<在ASP.NET MVC应用程序中随机获取一个字符串>http://www.cnblogs.com/insus/p/3 ...
- java 它 引用(基本类型的包装,构造函数和析构函数c++不同)
一个:java 和c++参考控制 他提到引用,我们会想到java它不喜欢c++里面的指针.当然java内引用和c++里面的引用是不同的. 比如: 比方C++中,我对某一个函数的声明.int a(i ...
- 探索Scala(1)-- 运算符重载
Scala语言运算符重载全然是语法层面的小把戏,本文记录我对Scala语言运算符重载的一些理解. 方法调用语法糖 调用方法时,Scala同意省略点号和圆括号,如以下代码所看到的: 把运算符映射成单词 ...
- DirectX 11游戏编程学习笔记2: 文章1章Vector Algebra(向量代数)
本文由哈里_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com 注:我给的电子版是700多页.而实体书是800多页,所以我在提到相关概念的时候.会使用章节号而 ...
- 类(class)能不能自己继承自己(转)
类(class)能不能自己继承自己不行,继承关系会出现环. 假设类A继承类A.那么要新建一个类A的对象,就必须先建立一个类A父类的对象.这是一个递归的过程,而且没有终止条件.会死循环的. 从编译的角度 ...
- nodejs安装:nodejs入门
nodejs开篇 前几天看到好多关于node 的帖子没有单独说明node安装的文章~ 特发此篇 总结一下平时在windows上nodejs的安装... 1.js来搞前后端分离是nodejs的一大特点, ...