日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > C# >内容正文

C#

c#扩展方法奇思妙用高级篇四:对扩展进行分组管理

發(fā)布時間:2023/12/13 C# 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c#扩展方法奇思妙用高级篇四:对扩展进行分组管理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
從系列文章開篇到現(xiàn)在,已經(jīng)實現(xiàn)的很多擴(kuò)展了,但過多的擴(kuò)展會給我們帶來很多麻煩,試看下圖:

?

?面對這么多“泛濫”的擴(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多個命名空間,很麻煩。

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

?

?圖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)后,方式二的顯示效果如下:

?

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

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

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

?

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

?

?

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

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

?首先定義一個接口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):??

Code
?1????public?interface?IExtension<V>
?2????{
?3????????V?GetValue();
?4????}

?5
?6????public?static?class?ExtensionGroup
?7????{
?8????????private?static?Dictionary<Type,?Type>?cache?=?new?Dictionary<Type,?Type>();
?9
10????????public?static?T?As<T>(this?string?v)?where?T?:?IExtension<string>
11????????{
12????????????return?As<T,?string>(v);
13????????}

14
15????????public?static?T?As<T,?V>(this?V?v)?where?T?:?IExtension<V>
16????????{
17????????????Type?t;
18????????????Type?valueType?=?typeof(V);
19????????????if?(cache.ContainsKey(valueType))
20????????????{
21????????????????t?=?cache[valueType];
22????????????}

23????????????else
24????????????{
25????????????????t?=?CreateType<T,?V>();
26????????????????cache.Add(valueType,?t);
27????????????}

28????????????object?result?=?Activator.CreateInstance(t,?v);
29????????????return?(T)result;
30????????}

31????????//?通過反射發(fā)出動態(tài)實現(xiàn)接口T
32????????private?static?Type?CreateType<T,?V>()?where?T?:?IExtension<V>
33????????{
34????????????Type?targetInterfaceType?=?typeof(T);
35????????????string?generatedClassName?=?targetInterfaceType.Name.Remove(0,?1);
36????????????//
37????????????AssemblyName?aName?=?new?AssemblyName("ExtensionDynamicAssembly");
38????????????AssemblyBuilder?ab?=
39????????????????AppDomain.CurrentDomain.DefineDynamicAssembly(aName,?AssemblyBuilderAccess.Run);
40????????????ModuleBuilder?mb?=?ab.DefineDynamicModule(aName.Name);
41????????????TypeBuilder?tb?=?mb.DefineType(generatedClassName,?TypeAttributes.Public);
42????????????//實現(xiàn)接口
43????????????tb.AddInterfaceImplementation(typeof(T));
44????????????//value字段
45????????????FieldBuilder?valueFiled?=?tb.DefineField("value",?typeof(V),?FieldAttributes.Private);
46????????????//構(gòu)造函數(shù)
47????????????ConstructorBuilder?ctor?=?tb.DefineConstructor(MethodAttributes.Public,
48????????????????CallingConventions.Standard,?new?Type[]?{?typeof(V)?});
49????????????ILGenerator?ctor1IL?=?ctor.GetILGenerator();
50????????????ctor1IL.Emit(OpCodes.Ldarg_0);
51????????????ctor1IL.Emit(OpCodes.Call,?typeof(object).GetConstructor(Type.EmptyTypes));
52????????????ctor1IL.Emit(OpCodes.Ldarg_0);
53????????????ctor1IL.Emit(OpCodes.Ldarg_1);
54????????????ctor1IL.Emit(OpCodes.Stfld,?valueFiled);
55????????????ctor1IL.Emit(OpCodes.Ret);
56????????????//GetValue方法
57????????????MethodBuilder?getValueMethod?=?tb.DefineMethod("GetValue",
58????????????????MethodAttributes.Public?|?MethodAttributes.Virtual,?typeof(V),?Type.EmptyTypes);
59????????????ILGenerator?numberGetIL?=?getValueMethod.GetILGenerator();
60????????????numberGetIL.Emit(OpCodes.Ldarg_0);
61????????????numberGetIL.Emit(OpCodes.Ldfld,?valueFiled);
62????????????numberGetIL.Emit(OpCodes.Ret);
63????????????//接口實現(xiàn)
64????????????MethodInfo?getValueInfo?=?targetInterfaceType.GetInterfaces()[0].GetMethod("GetValue");
65????????????tb.DefineMethodOverride(getValueMethod,?getValueInfo);
66????????????//
67????????????Type?t?=?tb.CreateType();
68????????????return?t;
69????????}

70????}

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

?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?????????}
12?????}

?如果此處不用反射發(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),大家多提些建議啊。

?最后,謝謝大家對我的運(yùn)行,特別感謝韋恩卑鄙

?本人系列文章《c#擴(kuò)展方法奇思妙用》,敬請關(guān)注!??

轉(zhuǎn)載于:https://www.cnblogs.com/China-Dragon/archive/2010/05/12/1733482.html

總結(jié)

以上是生活随笔為你收集整理的c#扩展方法奇思妙用高级篇四:对扩展进行分组管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。