使用扩展方法和接口给对象添加“重置状态”功能
2008-02-12 00:29 无常 阅读(2698) 评论(7) 收藏 举报项目中有些对象经常需要重置部分或全部属性到初始状态,想给这些类全部都加上个Reset()方法,又显得太冗余。Q.yuhen的这个Post中提出一种思路,使用默认构造函数来重置状态,这样实现:
| class MyClass |
| { |
| public int X { get; set; } |
| public string S { get; set; } |
| public MyClass() |
| { |
| X = 1234; |
| S = "abc"; |
| } |
| public void Reset() |
| { |
| var ctor = this.GetType().GetConstructor(BindingFlags.Instance | BindingFlags.Public, |
| null, new Type[0], null); |
| ctor.Invoke(this, null); |
| } |
| } |
这个方法很巧妙,但还是需要在每个类中都重复添加这个Reset()方法,而且每个都是相同的代码,不是很满意。
于是,探讨一种新的方法-----使用c#3.0的扩展方法(Extension Methods)功能来实现此功能,实现起来就二行代码。
| public static class ResetableImpl |
| { |
| public static void Reset(this object obj) |
| { |
| var ctor = obj.GetType().GetConstructor(BindingFlags.Instance | BindingFlags.Public, |
| null, new Type[0], null); |
| ctor.Invoke(obj, null); |
| } |
| } |
这样就给所有的类都扩展了Reset()方法。
可是,这样实现有个很大的局限性,就是这个类必需有个默认构造方法,而且是在默认构造方法中初始化才行,否则是在做无用功。另外,我们并不是所有的类都需要Reset()方法,这样直接给祖先object扩展也不太合情理。
再改进,配合接口使用。
先定义一个接口IResetable:
| public interface IResetable{} |
这个接口什么也不做,只是个幌子,然后我们给这个接口添加扩展方法。(有关给接口添加扩展方法的事项,可以看下蝈蝈俊.net的这个POST:C#3.0 中使用扩展方法来扩展接口。)
现在来修改一下这个添加扩展方法的这个class,将扩展对象由object改为IResetable接口:
| public static class ResetableImpl |
| { |
| public static void Reset(this IResetable obj) |
| { |
| var ctor = obj.GetType().GetConstructor(BindingFlags.Instance | BindingFlags.Public, |
| null, new Type[0], null); |
| ctor.Invoke(obj, null); |
| } |
| } |
然后,给我们的类加上IResetable接口,如这样:
| class Mail : IResetable |
| { |
| public string Subject { get; set; } |
| public string Body { get; set; } |
| public MailAddress From { get; set; } |
| public MailAddress To { get; set; } |
| public Mail() |
| { |
| this.Subject = ""; |
| this.Body = ""; |
| this.From = null; |
| this.To = null; |
| } |
| } |
使用的时候就很方便了:
不过,这样还是要求必需在默认构造方法中做初始化:(,似乎某本c#大作中也提倡在构造方法中初始化的。
如果担心每次调用时Reflection的性能太低,那再改进一下:
| public static class ResetableImpl |
| { |
| private static object lockObject = new object(); |
| private static Dictionary<string, ConstructorInfo> dct = new Dictionary<string, ConstructorInfo>(); |
| public static void Reset(this IResetable obj) |
| { |
| string key = obj.GetType().ToString(); |
| ConstructorInfo ctor =null ; |
| if ( dct.ContainsKey(key) ==false) |
| { |
| lock (lockObject) |
| { |
| if (dct.ContainsKey(key) == false) |
| { |
| ctor = obj.GetType().GetConstructor(BindingFlags.Instance | BindingFlags.Public, |
| null, new Type[0], null); |
| } |
| } |
| } |
| else |
| { |
| ctor = dct[key]; |
| } |
| ctor.Invoke(obj, null); |
| } |
| } |
浙公网安备 33010602011771号