我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C#如何对扩展进行分组管理

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C#如何对扩展进行分组管理

本篇内容主要讲解“C#如何对扩展进行分组管理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#如何对扩展进行分组管理”吧!

从系列文章开篇到现在,已经实现的很多扩展了,但过多的扩展会给我们带来很多麻烦,试看下图:

C#如何对扩展进行分组管理

C#扩展方法图1

面对这么多“泛滥”的扩展,很多人都会感到很别扭,的确有种“喧宾夺主”的感觉,想从中找出真正想用的方法来太难了!尽管经过扩展后的string类很“强大”,但易用性确很差。

很多人因此感觉扩展应适可而止,不该再继续下去...其实这是一种逃避问题的态度,出现问题我们应该主动去解决,而不是去回避!

有很多种方法可以解决以上问题,最简单的就是使用将扩展放入不同namespace中,使用时按需using相应namespace,可达到一定效果。但这种方法有很大缺点: 一个命名空间中的扩展若太多同样会让我们的智能提示充斥着扩展方法,扩展太少每次使用都要using多个命名空间,很麻烦。

先介绍一种简单的方式,先看效果:

C#如何对扩展进行分组管理

C#扩展方法图2

图1中前三个以As开始的三个扩展就是采用分组技术后的三类扩展,分别是中文处理、转换操作、正则操作,后面三个图分别对就这三类扩展的具体应用。图2中的有三个中文处理的扩展ToDBC、ToSBC、GetChineseSpell分别是转为半角、转为全角、获取拼音首字母。

通过这样分组后,string类的智能提示中扩展泛滥的现象得到了解决,使用AsXXX,是以字母A开始,会出现在提示的最前面,与原生方法区分开来。

采用这种方式有几个缺点:

使用一个扩展要先As一次,再使用具体扩展,比之前多了一步操作:这是分组管理必然的,建议使用频率非常高的还是直接扩展给string类,不要分组。只对使用频率不高的进行分组。

扩展后的智能提示不友好,扩展的方法与Equals、ToString混在了一起,而且没有扩展方法的标志。

先给出这种方法的实现参考代码,再来改进:

public static class StringExtension   {       public static ChineseString AsChineseString(this string s) { return new ChineseString(s); }       public static ConvertableString AsConvertableString(this string s) { return new ConvertableString(s); }       public static RegexableString AsRegexableString(this string s) { return new RegexableString(s); }   }   public class ChineseString   {       private string s;       public ChineseString(string s) { this.s = s; }       //转全角       public string ToSBC(string input) { throw new NotImplementedException(); }        //转半角       public string ToDBC(string input) { throw new NotImplementedException(); }       //获取汉字拼音首字母       public string GetChineseSpell(string input) { throw new NotImplementedException(); }   }   public class ConvertableString   {       private string s;       public ConvertableString(string s) { this.s = s; }       public bool IsInt(string s) { throw new NotImplementedException(); }       public bool IsDateTime(string s) { throw new NotImplementedException(); }       public int ToInt(string s) { throw new NotImplementedException(); }       public DateTime ToDateTime(string s) { throw new NotImplementedException(); }    }   public class RegexableString   {       private string s;       public RegexableString(string s) { this.s = s; }       public bool IsMatch(string s, string pattern) { throw new NotImplementedException(); }       public string Match(string s, string pattern) { throw new NotImplementedException(); }       public string Relplace(string s, string pattern, MatchEvaluator evaluator) { throw new NotImplementedException(); }   }

代码仅是为了说明怎么分组,没有实现,具体实现请参见本系列前面的文章。为了节省空间,很多代码都写成了一行。

前面提到的第二条缺点,我们改进后,方式二的显示效果如下:

C#如何对扩展进行分组管理

C#扩展方法图3

Equals、GetHashCode、ToString 实在去不了,哪位朋友有好办法分享一下吧!不过这次把扩展方法的标志加上。实现比方式一麻烦一下:

public class ChineseString  {      private string s;      public ChineseString(string s) { this.s = s; }      public string GetValue() { return s; }  }   public static class CheseStringExtension  {      public static ChineseString AsChineseString(this string s) { return new ChineseString(s); }       public static string ToSBC(this ChineseString cs)       {          string s = cs.GetValue();//从ChineseString取出原string          char[] c = s.ToCharArray();          for (int i = 0; i <  c.Length; i++)          {              if (c[i] == 32) { c[i] = (char)12288; continue; }                              if (c[i] <  127) c[i] = (char)(c[i] + 65248);          }          return new string(c);      }      public static string ToDBC(this ChineseString cs) { throw new NotImplementedException(); }      public static string GetChineseSpell(this ChineseString cs) { throw new NotImplementedException(); }  }

这里需要两个类,一个类ChineseString作为AsXXX的返回值,第二个类ChineseStringExtension是对ChineseString进行扩展的类。能过这种方式,才能显示出扩展的标识符号!每组扩展要两个类,比较麻烦。

方式一、方式二感觉都不太好,而且扩展组多了,还会有新的问题出现,如下:

C#如何对扩展进行分组管理

C#扩展方法图4

也是很要命的!再来看第三种方式,这是我和韦恩卑鄙在讨论单一职责原则时想出来的,先看效果:

C#如何对扩展进行分组管理

C#扩展方法图5

方法三将所有的扩展精简为一个As< T>!是的,我们仅需要As< T>这一个扩展!T为一接口,通过输入不同的T,展示相应的扩展。这样又解决了扩展组的泛滥问题,先看下实现一个新的扩展组需要写什么代码,先看左图的代码:

public interface IConvertableString : IExtension< string> { }   public static class ConvertableString  {      public static bool IsInt(this IConvertableString s)      {          int i; return int.TryParse(s.GetValue(), out i);      }      public static bool IsDateTime(this IConvertableString s)      {          DateTime d; return DateTime.TryParse(s.GetValue(), out d);      }       public static int ToInt(this IConvertableString s)      {          return int.Parse(s.GetValue());      }       public static DateTime ToDateTime(this IConvertableString s)      {         return DateTime.Parse(s.GetValue());      }  }

首先定义一个接口IConvertableString,它继承泛型接口IExtension< T>(我定义的一个接口,稍后给出),因为是对string类作扩展,所以泛型参数为string。IConvertableString只需要一个空架子。然后再编写一个扩展类,所有的方法扩展在IConvertableString接口上。

再来看右图IRegexableString的代码:

public static class RegexableString  {      public static bool IsMatch(this IRegexableString s, string pattern)      { throw new NotImplementedException(); }      public static string Match(this IRegexableString s, string pattern)      { throw new NotImplementedException(); }      public static string Relplace(this IRegexableString s, string pattern, MatchEvaluator evaluator)      { throw new NotImplementedException(); }  }

与上一个一样,也是先定义一个空接口,再定义一个扩展类,将方法扩展在空接口上。

有一点注意一下,扩展的实现中都要使用GetValue获取原始字符串的值。

***给出IExtension< T>接口及As< T>扩展的实现: 

public interface IExtension< V>  {      V GetValue();  }   public static class ExtensionGroup  {      private static Dictionary< Type, Type> cache = new Dictionary< Type, Type>();       public static T As< T>(this string v) where T : IExtension< string>      {          return As< T, string>(v);      }       public static T As< T, V>(this V v) where T : IExtension< V>      {          Type t;          Type valueType = typeof(V);          if (cache.ContainsKey(valueType))          {              t = cache[valueType];          }          else         {              t = CreateType< T, V>();              cache.Add(valueType, t);          }          object result = Activator.CreateInstance(t, v);          return (T)result;      }      // 通过反射发出动态实现接口T      private static Type CreateType< T, V>() where T : IExtension< V>      {          Type targetInterfaceType = typeof(T);          string generatedClassName = targetInterfaceType.Name.Remove(0, 1);          //          AssemblyName aName = new AssemblyName("ExtensionDynamicAssembly");          AssemblyBuilder ab =              AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);          ModuleBuilder mb = ab.DefineDynamicModule(aName.Name);          TypeBuilder tb = mb.DefineType(generatedClassName, TypeAttributes.Public);          //实现接口          tb.AddInterfaceImplementation(typeof(T));          //value字段          FieldBuilder valueFiled = tb.DefineField("value", typeof(V), FieldAttributes.Private);          //构造函数          ConstructorBuilder ctor = tb.DefineConstructor(MethodAttributes.Public,              CallingConventions.Standard, new Type[] { typeof(V) });          ILGenerator ctor1IL = ctor.GetILGenerator();          ctor1IL.Emit(OpCodes.Ldarg_0);          ctor1IL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));          ctor1IL.Emit(OpCodes.Ldarg_0);          ctor1IL.Emit(OpCodes.Ldarg_1);          ctor1IL.Emit(OpCodes.Stfld, valueFiled);          ctor1IL.Emit(OpCodes.Ret);          //GetValue方法          MethodBuilder getValueMethod = tb.DefineMethod("GetValue",              MethodAttributes.Public | MethodAttributes.Virtual, typeof(V), Type.EmptyTypes);          ILGenerator numberGetIL = getValueMethod.GetILGenerator();          numberGetIL.Emit(OpCodes.Ldarg_0);          numberGetIL.Emit(OpCodes.Ldfld, valueFiled);          numberGetIL.Emit(OpCodes.Ret);          //接口实现          MethodInfo getValueInfo = targetInterfaceType.GetInterfaces()[0].GetMethod("GetValue");          tb.DefineMethodOverride(getValueMethod, getValueInfo);          //          Type t = tb.CreateType();          return t;      }  }

代码比较长,先折叠起来,逐层打开分析吧!

IExtension< V>只定义一个方法GetValue,用于将As< T>后将原始的值取出。

ExtensionGroup定义了As< T>扩展,我们先看下值的传递过程。调用语句:"123".As< IConvertableString>().ToInt();

首先,"123" 是个字符串,As< IConvertableString>后转换成了IConvertableString接口的实例,ToInt时使用GetValue将"123"从IConvertableString接口的实例中取出进行处理。

关键在“IConvertableString接口的实例”,前面我们并没有具体实现IConvertableString接口的类,怎么出来的实例呢?我们这里用反射发出动态生成了一个实现IConvertableString接口的类。具体是由ExtensionGroup中的私有函数CreateType< T, V>完成的,在这里T传入的是IConvertableString,V传入的是string,返回的值就是实现了IConvertableString接口的一个类的Type.由CreateType< T, V>动态实现的类“模样”如下:

class ConvertableString : IConvertableString  {      private string value;      public ConvertableString(string value)      {              this.value = value;      }      public string GetValue()      {         return value;     }

如果此处不用反射发出动态生成这么一个,那么我们就要手工写一个,每个扩展组都要相应的写一个,很麻烦的。

为了提高性能,对反射发出的类型进行了缓存,保存在cache成员中。

方式三有点复杂,主要是因为我们是给sealed类进行扩展,无法从它们继承。

***给出测试代码:

public static void Test()  {      int i = "123".As< IConvertableString>().ToInt();      DateTime d = "2009年8月29日".As< IConvertableString>().ToDateTime();  }

三种方式,我最喜欢第三种,它仅需要一个As< T>,而且是对接口进行扩展,感觉更OO一些。

三种方式都不***,我会努力改进,大家多提些建议啊。

到此,相信大家对“C#如何对扩展进行分组管理”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C#如何对扩展进行分组管理

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C#如何对扩展进行分组管理

本篇内容主要讲解“C#如何对扩展进行分组管理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#如何对扩展进行分组管理”吧!从系列文章开篇到现在,已经实现的很多扩展了,但过多的扩展会给我们带来很多
2023-06-17

如何对Flume进行水平扩展

Flume是一个可扩展的日志收集系统,可以通过增加更多的Flume agent或者启动更多的Flume节点来实现水平扩展。以下是一些可能的方法:添加更多的Flume agent:可以在不同的机器上启动多个Flume agent,每个 age
如何对Flume进行水平扩展
2024-03-08

LVM中如何对xfs进行扩展

本篇内容介绍了“LVM中如何对xfs进行扩展”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. LVM基本术语物理卷 (physical v
2023-06-28

如何进行管理浏览历史的Chrome扩展History 2

这篇文章给大家介绍如何进行管理浏览历史的Chrome扩展History 2,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Chrome的历史记录会按照日期把你所有看过的网页都列出来,尽管你可以通过搜索来查找,但看着还是闹
2023-06-16

Win10如何对扩展显示屏进行操作的

这篇文章主要讲解了“Win10如何对扩展显示屏进行操作的”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Win10如何对扩展显示屏进行操作的”吧!具体方法:1.驱动安装后,电脑的任务栏会出现一
2023-06-27

如何进行C++内存管理?

如何进行C++内存管理?C++是一种强大的编程语言,但是它也要求开发者负责内存管理。在C++中,内存管理是非常重要的,因为错误的内存使用可能导致内存泄漏、野指针和其他一系列问题。因此,对于C++开发者来说,掌握良好的内存管理技巧至关重要。C
如何进行C++内存管理?
2023-11-02

C++开发建议:如何进行C++代码的扩展性设计

C++作为一种功能强大的编程语言,被广泛应用于软件开发领域。在进行C++代码的开发过程中,一个重要的考虑因素就是代码的扩展性设计。好的扩展性设计可以使代码更易于扩展和维护,提高开发效率和代码质量。本文将就C++代码的扩展性设计提出一些建议。
C++开发建议:如何进行C++代码的扩展性设计
2023-11-22

如何对Kubernetes对象的状态进行管理

这篇文章的内容主要围绕如何对Kubernetes对象的状态进行管理进行讲述,文章内容清晰易懂,条理清晰,非常适合新手学习,值得大家去阅读。感兴趣的朋友可以跟随小编一起阅读吧。希望大家通过这篇文章有所收获!我们下面主要聚焦于探究如何对Kube
2023-06-04

如何对C++链表进行解读分析

如何对C++链表进行解读分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。C++语言是学习数据结构的很好的学习工具,能够全面的理解了C++中C++链表的作用和用途,那么对于理解
2023-06-17

如何使用阿里云ECS进行C盘分区管理

在使用阿里云ECS进行数据存储和管理时,C盘分区的管理是非常重要的一步。本篇文章将详细讲解如何使用阿里云ECS进行C盘分区管理。在阿里云ECS中,C盘分区是指用于存放操作系统和应用程序的磁盘分区。在使用ECS的过程中,如果C盘分区不足,可能会导致系统运行缓慢,甚至无法正常运行。因此,我们需要定期对C盘分区进行管理
如何使用阿里云ECS进行C盘分区管理
2023-12-16

使用Maven如何对项目进行管理

使用Maven如何对项目进行管理?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。使用 Maven 管理项目时,三层的开发时分模块开发的,parent-dao-se
2023-05-31

如何使用数组进行内存管理?

数组是一种保存在连续内存空间中的元素集合,使用单个变量访问多个相关值。通过索引(从 0 开始)访问数组元素。动态内存分配允许使用 malloc 和 free 函数创建数组。示例:学生信息数组案例,使用结构 student 存储姓名、学号和成
如何使用数组进行内存管理?
2024-05-24

如何进行C++代码的内存管理?

如何进行C++代码的内存管理?C++是一种功能强大的编程语言,但同时也要求程序员自行管理内存。正确的内存管理是确保程序运行稳定和高效的关键之一。本文将介绍一些常见的内存管理技术和最佳实践,帮助初学者和有经验的开发人员更好地管理C++代码的内
如何进行C++代码的内存管理?
2023-11-03

如何进行C++代码的日志管理?

随着软件开发的不断发展,日志管理已经变成了代码开发过程中必不可少的部分,而C++作为一门较为复杂的编程语言,在进行代码开发时也需要进行日志管理。本文将介绍C++代码的日志管理原则及具体实现,希望对读者有所帮助。一、日志管理原则确定日志级别日
如何进行C++代码的日志管理?
2023-11-03

如何进行C++代码的依赖管理?

如何进行C++代码的依赖管理?作为一种广泛使用的编程语言,C++常常用于开发涉及底层硬件、系统级别或具有高性能要求的应用程序。在实际开发中,C++项目往往会涉及到各种库、框架和其他依赖项,因此,进行代码的依赖管理变得尤为重要。本文将介绍几种
如何进行C++代码的依赖管理?
2023-11-04

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录