方法三將所有的擴展精簡為一個As<T>!是的,我們僅需要As<T>這一個擴展!T為一接口,通過輸入不同的T,展示相應的擴展。這樣又解決了擴展組的泛濫問題,先看下實現一個新的擴展組需要寫什麼代碼,先看左圖的代碼:
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類作擴展,所以泛型參數為string。IConvertableString只需要一個空架子。然後再編寫一個擴展類,所有的方法擴展在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 }
與上一個一樣,也是先定義一個空接口,再定義一個擴展類,將方法擴展在空接口上。
有一點注意一下,擴展的實現中都要使用GetValue獲取原始字符串的值。
最後給出IExtension<T>接口及As<T>擴展的實現:
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 // 通過反射發出動態實現接口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 //實現接口
43 tb.AddInterfaceImplementation(typeof(T));
44 //value字段
45 FieldBuilder valueFiled = tb.DefineField("value", typeof(V), FIEldAttributes.Private);
46 //構造函數
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 //接口實現
64 MethodInfo getValueInfo = targetInterfaceType.GetInterfaces()[0].GetMethod("GetValue");
65 tb.DefineMethodOverride(getValueMethod, getValueInfo);
66 //
67 Type t = tb.CreateType();
68 return t;
69 }
70 }