日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
C#擴(kuò)展方法:對擴(kuò)展進(jìn)行分組管理

從系列文章開篇到現(xiàn)在,已經(jīng)實現(xiàn)的很多擴(kuò)展了,但過多的擴(kuò)展會給我們帶來很多麻煩,試看下圖:

10年積累的網(wǎng)站設(shè)計、成都網(wǎng)站設(shè)計經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有西盟免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

C#擴(kuò)展方法圖1

面對這么多“泛濫”的擴(kuò)展,很多人都會感到很別扭,的確有種“喧賓奪主”的感覺,想從中找出真正想用的方法來太難了!盡管經(jīng)過擴(kuò)展后的string類很“強(qiáng)大”,但易用性確很差。

很多人因此感覺擴(kuò)展應(yīng)適可而止,不該再繼續(xù)下去...其實這是一種逃避問題的態(tài)度,出現(xiàn)問題我們應(yīng)該主動去解決,而不是去回避!

有很多種方法可以解決以上問題,最簡單的就是使用將擴(kuò)展放入不同namespace中,使用時按需using相應(yīng)namespace,可達(dá)到一定效果。但這種方法有很大缺點: 一個命名空間中的擴(kuò)展若太多同樣會讓我們的智能提示充斥著擴(kuò)展方法,擴(kuò)展太少每次使用都要using多個命名空間,很麻煩。

 先介紹一種簡單的方式,先看效果:

C#擴(kuò)展方法圖2

圖1中前三個以As開始的三個擴(kuò)展就是采用分組技術(shù)后的三類擴(kuò)展,分別是中文處理、轉(zhuǎn)換操作、正則操作,后面三個圖分別對就這三類擴(kuò)展的具體應(yīng)用。圖2中的有三個中文處理的擴(kuò)展ToDBC、ToSBC、GetChineseSpell分別是轉(zhuǎn)為半角、轉(zhuǎn)為全角、獲取拼音首字母。

 通過這樣分組后,string類的智能提示中擴(kuò)展泛濫的現(xiàn)象得到了解決,使用AsXXX,是以字母A開始,會出現(xiàn)在提示的最前面,與原生方法區(qū)分開來。

 采用這種方式有幾個缺點:

 1.使用一個擴(kuò)展要先As一次,再使用具體擴(kuò)展,比之前多了一步操作:這是分組管理必然的,建議使用頻率非常高的還是直接擴(kuò)展給string類,不要分組。只對使用頻率不高的進(jìn)行分組。

 2.擴(kuò)展后的智能提示不友好,擴(kuò)展的方法與Equals、ToString混在了一起,而且沒有擴(kuò)展方法的標(biāo)志。

 先給出這種方法的實現(xiàn)參考代碼,再來改進(jìn):

 
 
 
 
  1. public static class StringExtension
  2.  {
  3.      public static ChineseString AsChineseString(this string s) { return new ChineseString(s); }
  4.      public static ConvertableString AsConvertableString(this string s) { return new ConvertableString(s); }
  5.      public static RegexableString AsRegexableString(this string s) { return new RegexableString(s); }
  6.  }
  7.  public class ChineseString
  8.  {
  9.      private string s;
  10.      public ChineseString(string s) { this.s = s; }
  11.      //轉(zhuǎn)全角
  12.      public string ToSBC(string input) { throw new NotImplementedException(); } 
  13.      //轉(zhuǎn)半角
  14.      public string ToDBC(string input) { throw new NotImplementedException(); }
  15.      //獲取漢字拼音首字母
  16.      public string GetChineseSpell(string input) { throw new NotImplementedException(); }
  17.  }
  18.  public class ConvertableString
  19.  {
  20.      private string s;
  21.      public ConvertableString(string s) { this.s = s; }
  22.      public bool IsInt(string s) { throw new NotImplementedException(); }
  23.      public bool IsDateTime(string s) { throw new NotImplementedException(); }
  24.      public int ToInt(string s) { throw new NotImplementedException(); }
  25.      public DateTime ToDateTime(string s) { throw new NotImplementedException(); } 
  26.  }
  27.  public class RegexableString
  28.  {
  29.      private string s;
  30.      public RegexableString(string s) { this.s = s; }
  31.      public bool IsMatch(string s, string pattern) { throw new NotImplementedException(); }
  32.      public string Match(string s, string pattern) { throw new NotImplementedException(); }
  33.      public string Relplace(string s, string pattern, MatchEvaluator evaluator) { throw new NotImplementedException(); }
  34.  }

 代碼僅是為了說明怎么分組,沒有實現(xiàn),具體實現(xiàn)請參見本系列前面的文章。為了節(jié)省空間,很多代碼都寫成了一行。

 前面提到的第二條缺點,我們改進(jìn)后,方式二的顯示效果如下:

C#擴(kuò)展方法圖3

 Equals、GetHashCode、ToString 實在去不了,哪位朋友有好辦法分享一下吧!不過這次把擴(kuò)展方法的標(biāo)志加上。實現(xiàn)比方式一麻煩一下:

 
 
 
 
  1. public class ChineseString
  2. {
  3.     private string s;
  4.     public ChineseString(string s) { this.s = s; }
  5.     public string GetValue() { return s; }
  6. }
  7. public static class CheseStringExtension
  8. {
  9.     public static ChineseString AsChineseString(this string s) { return new ChineseString(s); }
  10.     public static string ToSBC(this ChineseString cs) 
  11.     {
  12.         string s = cs.GetValue();//從ChineseString取出原string
  13.         char[] c = s.ToCharArray();
  14.         for (int i = 0; i <  c.Length; i++)
  15.         {
  16.             if (c[i] == 32) { c[i] = (char)12288; continue; }                
  17.             if (c[i] <  127) c[i] = (char)(c[i] + 65248);
  18.         }
  19.         return new string(c);
  20.     }
  21.     public static string ToDBC(this ChineseString cs) { throw new NotImplementedException(); }
  22.     public static string GetChineseSpell(this ChineseString cs) { throw new NotImplementedException(); }
  23. }

這里需要兩個類,一個類ChineseString作為AsXXX的返回值,第二個類ChineseStringExtension是對ChineseString進(jìn)行擴(kuò)展的類。能過這種方式,才能顯示出擴(kuò)展的標(biāo)識符號!每組擴(kuò)展要兩個類,比較麻煩。

方式一、方式二感覺都不太好,而且擴(kuò)展組多了,還會有新的問題出現(xiàn),如下:

C#擴(kuò)展方法圖4

也是很要命的!再來看第三種方式,這是我和韋恩卑鄙在討論單一職責(zé)原則時想出來的,先看效果:

C#擴(kuò)展方法圖5

 方法三將所有的擴(kuò)展精簡為一個As< T>!是的,我們僅需要As< T>這一個擴(kuò)展!T為一接口,通過輸入不同的T,展示相應(yīng)的擴(kuò)展。這樣又解決了擴(kuò)展組的泛濫問題,先看下實現(xiàn)一個新的擴(kuò)展組需要寫什么代碼,先看左圖的代碼:

 
 
 
 
  1. public interface IConvertableString : IExtension< string> { }
  2. public static class ConvertableString
  3. {
  4.     public static bool IsInt(this IConvertableString s)
  5.     {
  6.         int i; return int.TryParse(s.GetValue(), out i);
  7.     }
  8.     public static bool IsDateTime(this IConvertableString s)
  9.     {
  10.         DateTime d; return DateTime.TryParse(s.GetValue(), out d);
  11.     }
  12.     public static int ToInt(this IConvertableString s)
  13.     {
  14.         return int.Parse(s.GetValue());
  15.     }
  16.     public static DateTime ToDateTime(this IConvertableString s)
  17.     {
  18.        return DateTime.Parse(s.GetValue());
  19.     }
  20. }

首先定義一個接口IConvertableString,它繼承泛型接口IExtension< T>(我定義的一個接口,稍后給出),因為是對string類作擴(kuò)展,所以泛型參數(shù)為string。IConvertableString只需要一個空架子。然后再編寫一個擴(kuò)展類,所有的方法擴(kuò)展在IConvertableString接口上。

再來看右圖IRegexableString的代碼:

 
 
 
 
  1. public static class RegexableString
  2. {
  3.     public static bool IsMatch(this IRegexableString s, string pattern)
  4.     { throw new NotImplementedException(); }
  5.     public static string Match(this IRegexableString s, string pattern)
  6.     { throw new NotImplementedException(); }
  7.     public static string Relplace(this IRegexableString s, string pattern, MatchEvaluator evaluator)
  8.     { throw new NotImplementedException(); }
  9. }

與上一個一樣,也是先定義一個空接口,再定義一個擴(kuò)展類,將方法擴(kuò)展在空接口上。

 有一點注意一下,擴(kuò)展的實現(xiàn)中都要使用GetValue獲取原始字符串的值。

 ***給出IExtension< T>接口及As< T>擴(kuò)展的實現(xiàn):

 
 
 
 
  1. public interface IExtension< V>
  2. {
  3.     V GetValue();
  4. }
  5. public static class ExtensionGroup
  6. {
  7.     private static Dictionary< Type, Type> cache = new Dictionary< Type, Type>();
  8.     public static T As< T>(this string v) where T : IExtension< string>
  9.     {
  10.         return As< T, string>(v);
  11.     }
  12.     public static T As< T, V>(this V v) where T : IExtension< V>
  13.     {
  14.         Type t;
  15.         Type valueType = typeof(V);
  16.         if (cache.ContainsKey(valueType))
  17.         {
  18.             t = cache[valueType];
  19.         }
  20.         else
  21.         {
  22.             t = CreateType< T, V>();
  23.             cache.Add(valueType, t);
  24.         }
  25.         object result = Activator.CreateInstance(t, v);
  26.         return (T)result;
  27.     }
  28.     // 通過反射發(fā)出動態(tài)實現(xiàn)接口T
  29.     private static Type CreateType< T, V>() where T : IExtension< V>
  30.     {
  31.         Type targetInterfaceType = typeof(T);
  32.         string generatedClassName = targetInterfaceType.Name.Remove(0, 1);
  33.         //
  34.         AssemblyName aName = new AssemblyName("ExtensionDynamicAssembly");
  35.         AssemblyBuilder ab =
  36.             AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);
  37.         ModuleBuilder mb = ab.DefineDynamicModule(aName.Name);
  38.         TypeBuilder tb = mb.DefineType(generatedClassName, TypeAttributes.Public);
  39.         //實現(xiàn)接口
  40.         tb.AddInterfaceImplementation(typeof(T));
  41.         //value字段
  42.         FieldBuilder valueFiled = tb.DefineField("value", typeof(V), FieldAttributes.Private);
  43.         //構(gòu)造函數(shù)
  44.         ConstructorBuilder ctor = tb.DefineConstructor(MethodAttributes.Public,
  45.             CallingConventions.Standard, new Type[] { typeof(V) });
  46.         ILGenerator ctor1IL = ctor.GetILGenerator();
  47.         ctor1IL.Emit(OpCodes.Ldarg_0);
  48.         ctor1IL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
  49.         ctor1IL.Emit(OpCodes.Ldarg_0);
  50.         ctor1IL.Emit(OpCodes.Ldarg_1);
  51.         ctor1IL.Emit(OpCodes.Stfld, valueFiled);
  52.         ctor1IL.Emit(OpCodes.Ret);
  53.         //GetValue方法
  54.         MethodBuilder getValueMethod = tb.DefineMethod("GetValue",
  55.             MethodAttributes.Public | MethodAttributes.Virtual, typeof(V), Type.EmptyTypes);
  56.         ILGenerator numberGetIL = getValueMethod.GetILGenerator();
  57.         numberGetIL.Emit(OpCodes.Ldarg_0);
  58.         numberGetIL.Emit(OpCodes.Ldfld, valueFiled);
  59.         numberGetIL.Emit(OpCodes.Ret);
  60.         //接口實現(xiàn)
  61.         MethodInfo getValueInfo = targetInterfaceType.GetInterfaces()[0].GetMethod("GetValue");
  62.         tb.DefineMethodOverride(getValueMethod, getValueInfo);
  63.         //
  64.         Type t = tb.CreateType();
  65.         return t;
  66.     }
  67. }

代碼比較長,先折疊起來,逐層打開分析吧!

IExtension< V>只定義一個方法GetValue,用于將As< T>后將原始的值取出。

ExtensionGroup定義了As< T>擴(kuò)展,我們先看下值的傳遞過程。調(diào)用語句:"123".As< IConvertableString>().ToInt();

首先,"123" 是個字符串,As< IConvertableString>后轉(zhuǎn)換成了IConvertableString接口的實例,ToInt時使用GetValue將"123"從IConvertableString接口的實例中取出進(jìn)行處理。

關(guān)鍵在“IConvertableString接口的實例”,前面我們并沒有具體實現(xiàn)IConvertableString接口的類,怎么出來的實例呢?我們這里用反射發(fā)出動態(tài)生成了一個實現(xiàn)IConvertableString接口的類。具體是由ExtensionGroup中的私有函數(shù)CreateType< T, V>完成的,在這里T傳入的是IConvertableString,V傳入的是string,返回的值就是實現(xiàn)了IConvertableString接口的一個類的Type.由CreateType< T, V>動態(tài)實現(xiàn)的類“模樣”如下:

 
 
 
 
  1. class ConvertableString : IConvertableString
  2. {
  3.     private string value;
  4.     public ConvertableString(string value)
  5.     {
  6.             this.value = value;
  7.     }
  8.     public string GetValue()
  9.     {
  10.        return value;
  11.    }

如果此處不用反射發(fā)出動態(tài)生成這么一個,那么我們就要手工寫一個,每個擴(kuò)展組都要相應(yīng)的寫一個,很麻煩的。

為了提高性能,對反射發(fā)出的類型進(jìn)行了緩存,保存在cache成員中。

方式三有點復(fù)雜,主要是因為我們是給sealed類進(jìn)行擴(kuò)展,無法從它們繼承。

***給出測試代碼:

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

三種方式,我最喜歡第三種,它僅需要一個As< T>,而且是對接口進(jìn)行擴(kuò)展,感覺更OO一些。

三種方式都不***,我會努力改進(jìn),大家多提些建議啊。


當(dāng)前題目:C#擴(kuò)展方法:對擴(kuò)展進(jìn)行分組管理
本文網(wǎng)址:http://www.5511xx.com/article/cdehcgg.html