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添加 ...
随机推荐
- eclipse 在win7 64两个图标出现位操作系统无法锁定到任务栏或任务栏
eclipse 在win7 64位操作系统无法锁定到任务栏或者任务栏上出现两个图标 解决的方法 eclipse在win7 64bit下无法锁定到任务栏问题(或是锁定后任务栏出现两个eclipse图标) ...
- PHP上传文件(学习)
<?php if(isset($_FILES['upfile'])) { if (is_uploaded_file($_FILES['upfile']['tmp_name'])){ $upfil ...
- UVA 193 Graph Coloring 图染色 DFS 数据
题意:图上的点染色,给出的边的两个点不能都染成黑色,问最多可以染多少黑色. 很水的一题,用dfs回溯即可.先判断和当前点相连的点是否染成黑色,看这一点是否能染黑色,能染色就分染成黑色和白色两种情况递归 ...
- C#值传递和按引用传递
知识点: 值类型和引用类型 为值类型,,据 对于引用类型来说,栈中存储的是堆中对象的地址 值传递和引用传递 对于值传递,传递的是栈中保存的数据 对于引用传递.传递的是栈本 ...
- 使用Django清理数据库中的数据
数据库,数据清洗 问题叙述性说明:在系统我用在,因为历史和由于各种原因,原因记录的数据内的数据库表,有一个问题,有反复和不完整的数据 解:首先.由于数据量还是挺大的,工的清理肯定不行, 然后,我就想写 ...
- 恢复SQLSERVER被误删除的数据
原文:恢复SQLSERVER被误删除的数据 恢复SQLSERVER被误删除的数据 曾经想实现Log Explorer for SQL Server的功能,利用ldf里面的日志来还原误删除的数据 这里有 ...
- iphone手机版降级
想减少移动版本号.你能下载下来你想要的版本在苹果开发者网站,或"信誉"或可以下载到其他网站的iPhone下载固件固件网站.然后打开iTunes,进入 然后按着(alt).同一时候用 ...
- 使用 CodeIgniter 框架快速开发 PHP 应用(一)
原文:使用 CodeIgniter 框架快速开发 PHP 应用(一) 对 CodeIgniter 的介绍大多数PHPer都想写出运行状态良好的应用程序,而且希望尽可能做得简单且不费事.这篇文章是有关 ...
- 华为OJ: 公共字符串计算
有几个需要注意的地方,这个问题是不是大写和小写之间的区别.这样你就输入字符串大写或小写转换的计算前. 第二个,定要清晰.先将s1从[i]处開始与s2的[j]開始匹配,不相等则j++直到j等于s2.le ...
- 采用oracle官方文件(11G)——初步Concept
采用oracle官方文件(11G)示例 这里是oracle官方文档界面,想了解oracle,阅读官方文档是唯一的方法,大致了解官方文档的使用,对官方文档有一个更直观的认识.文档可通过文章关联的链接查看 ...