通用序列化基类 只须实现该类抽象成员即可进行序列化与反序列化
转载请注明出处 http://www.cnblogs.com/68681395
1//是否写日志
2#define txtLogAll
3
4using System;
5using System.Web;
6using System.Xml.Serialization;
7using System.IO;
8using System.Runtime.Serialization;
9using System.Runtime.Serialization.Formatters.Soap;
10using System.Runtime.Serialization.Formatters.Binary;
11using System.Web.Caching;
12using System.Threading;
13using tjb.Utility.Caching;
14using System.Xml;
15using System.Text;
16
17
18namespace tjb.Utility.Config
19{
20
21 文件序列化的类型#region 文件序列化的类型
22 /**//// <summary>
23 /// 序列化文件的方式
24 /// Binary,Xml,SoapXml
25 /// </summary>
26 public enum Formatter
27 {
28 /**//// <summary>
29 /// 字节
30 /// </summary>
31 Binary,
32 /**//// <summary>
33 /// xml
34 /// </summary>
35 Xml,
36 /**//// <summary>
37 /// soap协议的xml
38 /// </summary>
39 SoapXml
40 }
41 #endregion
42
43 /**//// <summary>
44 /// 序列化基类 by Tjb 2007/06
45 /// T 类型不能创建多态的多个实例
46 /// 优化和修正,增加配置文件备份 2008/9/18
47 /// 修改:获取实例时加锁
48 /// 修改:
49 /// SaveAs(T Tobj, string FileFullName, bool BackupOnError) 方法增加线程锁定。防止多线程冲突 2008/10/24
50 /// </summary>
51 /// <typeparam name="T">T 必须有无参数的构造函数</typeparam>
52 [Serializable]
53 public abstract class IConfig<T> where T : IConfig<T>, new()
54 {
55
56 Exceptions#region Exceptions
57 private Exception __ConfigException;
58 /**//// <summary>
59 /// 读取或保存时发生的错误
60 /// </summary>
61 [XmlIgnore, SoapIgnore]
62 public Exception Exception
63 {
64 get
65 {
66 return __ConfigException;
67 }
68 private set
69 {
70 if (value != null)
71 {
72 HasError = true;
73 __ConfigException = value;
74#if txtLogAll
75 Log.WriteLog(value);
76#endif
77 }
78 }
79 }
80 private bool __HasError = false;
81 /**//// <summary>
82 /// 获取一个值 指示读取或者保存时是否发生错误
83 /// 如果当前错误被获取后,此标志将被置为false
84 /// </summary>
85 [XmlIgnore, SoapIgnore]
86 public bool HasError
87 {
88 get { return __HasError; }
89 private set { __HasError = value; }
90 }
91 #endregion
92
93 序列化类型 可重写#region 序列化类型 可重写
94
95 private Formatter _CurrentFormatter = Formatter.Xml;
96 /**//// <summary>
97 /// 序列化的方式
98 /// </summary>
99 [XmlIgnore]
100 protected virtual Formatter CurrentFormatter
101 {
102 get
103 {
104 return _CurrentFormatter;
105 }
106 set
107 {
108 _CurrentFormatter = value;
109 }
110 }
111
112 #endregion
113
114 获取单个实例#region 获取单个实例
115
116 /**//// <summary>
117 /// 获取Cache中缓存T的key
118 /// </summary>
119 public static string CacheKEY
120 {
121 get
122 {
123 // return typeof(T).GUID.ToString("N");
124 return typeof(T).FullName;
125 }
126 }
127 /**//// <summary>
128 /// 从缓存(缓存KEY为T的命空间加类名)获取当前类的实例,如果缓存不存在则读取文件(ConfigFileFullName), 并缓存。
129 /// </summary>
130 public static T Instance
131 {
132 get
133 {
134 T c = CacheUtility.Get<T>(CacheKEY);
135 if (c == null)
136 {
137 //这中方式无异于不加锁
138 //object Monitor = new object();
139 //lock (Monitor)
140 lock (typeof(T))
141 {
142 c = CacheUtility.Get<T>(CacheKEY);
143 if (c == null)
144 {
145 c = new T().Read();
146#if DEBUG
147 CacheUtility.SetSlidingExpiration(CacheKEY, c, c.ConfigFileFullName, 7, CacheItemPriority.NotRemovable, new CacheItemRemovedCallback(CallR));
148#else
149 CacheUtility.SetSlidingExpiration(CacheKEY, c, c.ConfigFileFullName, 7, CacheItemPriority.NotRemovable, null);
150#endif
151 }
152 }
153 }
154 return c;
155 }
156 }
157
158 #endregion
159
160 Caching..#region Caching..
161
162 /**//// <summary>
163 /// 从ConfigFileName指定文件以CurrentSerializeType读取实例,如果存在缓存则移除并重新进行缓存
164 /// 如果不存在则以InitConfig初始化类,创建并保存文件
165 /// </summary>
166 /// <returns></returns>
167 protected T ResetCacheAndRead()
168 {
169 ResetCache();
170 return Read();
171 }
172 /**//// <summary>
173 /// 移除CacheKEY 缓存
174 /// </summary>
175 public void ResetCache()
176 {
177 HttpRuntime.Cache.Remove(CacheKEY);
178 }
179 #endregion
180
181 获取#region 获取
182
183 /**//// <summary>
184 /// 读取缓存中的实例如果不存在则
185 /// 从ConfigFileName指定文件以CurrentSerializeType读取实例
186 /// 如果不存在则以InitConfig初始化类,创建并保存文件
187 /// </summary>
188 /// <returns></returns>
189 virtual protected T Read()
190 {
191 return Read(ConfigFileFullName, true, CurrentFormatter);
192 }
193
194 /**//// <summary>
195 /// 从ConfigFileName指定文件以CurrentSerializeType读取实例
196 /// 如果不存在则以InitConfig初始化类,创建并保存文件
197 /// </summary>
198 /// <param name="configFileFullName">缓存文件绝对路径</param>
199 /// <param name="serializeType"></param>
200 /// <param name="BackupOnError">读取错误时是否备份</param>
201 /// <returns></returns>
202 protected T Read(string configFileFullName, bool BackupOnError, Formatter serializeType)
203 {
204 T t = CacheUtility.Get<T>(CacheKEY);
205 if (t != null)
206 return t;
207 FileInfo fi = new FileInfo(configFileFullName);
208 if (fi.Exists)
209 {
210
211 FileStream fs = null;
212 try
213 {
214 open the stream#region open the stream
215 // open the stream
216 fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
217 IFormatter formatter = null;
218 switch (serializeType)
219 {
220 case Formatter.Binary:
221 formatter = new BinaryFormatter();
222 t = formatter.Deserialize(fs) as T;
223 break;
224 case Formatter.SoapXml:
225 formatter = new SoapFormatter();
226 t = formatter.Deserialize(fs) as T;
227 break;
228 case Formatter.Xml:
229 XmlSerializer serializer = new XmlSerializer(typeof(T));
230 t = serializer.Deserialize(fs) as T;
231 break;
232 default:
233 break;
234 }
235 #endregion
236
237 if (fs != null)
238 fs.Close();
239 }
240 catch (Exception ex)
241 {
242 if (fs != null)
243 fs.Close();
244 t = CustomizingInit();
245
246 读取失败 进行备份 防止以后使用默认配置覆盖当前数据#region 读取失败 进行备份 防止以后使用默认配置覆盖当前数据
247 if (BackupOnError)
248 if (fi.Exists)
249 {
250 string BackupFilePath = fi.FullName + ".Read." + DateTime.Now.ToString("yyMMddHHssfff") + ".bak";
251 try
252 {
253 fi.CopyTo(BackupFilePath, true);
254 t.Save(true);
255 }
256 catch (Exception ioex)
257 {
258 t.Exception = new Exception("读取配置文件出错后,对配置文件进行备份发生错误!", ioex);
259 }
260 }
261 #endregion
262
263 t.Exception = new Exception("读取配置文件时发生错误!将返回CustomizingInit()方法的实例,默认为 new T()!", ex);
264 }
265 finally
266 {
267
268 }
269 }
270 else
271 {
272 t = CustomizingInit();
273
274 //不存在的同一文件不能读多次
275 //防止在CustomizingInit()方法中调用Read(string configFileName, SerializeType serializeType) 造成死循环
276 string ProtectedKEY = Thread.CurrentThread.ManagedThreadId + fi.FullName + "init";
277 if (CacheUtility.GetAnyType<bool>(ProtectedKEY) == false)
278 {
279 CacheUtility.SetAbsoluteExpiration(ProtectedKEY, true, null, 0.02);
280 }
281 else
282 {
283 CacheUtility.Remove(ProtectedKEY);
284 throw new Exception("'" + fi.FullName + "' 文件不存在!读取过于频繁。导致此保护异常发生。");
285 }
286 t.Exception = new Exception("配置文件:'" + fi.FullName + "' 不存在!默认返回CustomizingInit()方法返回的实例。");
287 }
288 if (t == null)
289 t.Exception = new Exception("发生错误,请检查初始化配置方法 CustomizingInit() 未返回的配置实例不能为空,或者系统中存在缓存 key :" + CacheKEY);
290 return t;
291 }
292
293#if DEBUG
294 private static void CallR(string key, object obj, CacheItemRemovedReason re)
295 {
296#if txtLogAll
297 Log.WriteLog(key + "::::" + re.ToString());
298#endif
299 }
300#endif
301
302 #endregion
303
304 保存#region 保存
305 /**//// <summary>
306 /// 将当前实例进行保存
307 /// </summary>
308 /// <param name="BackupOnError">发生错误时是否备份</param>
309 /// <returns></returns>
310 public bool Save(bool BackupOnError)
311 {
312 if (Current == null)
313 {
314 Exception = new Exception(typeof(T).FullName + " 未正确实现 Current;");
315 return false;
316 }
317 return Save(Current, BackupOnError);
318 }
319 /**//// <summary>
320 /// 将当前实例进行保存
321 /// 发生错误时将备份配置文件
322 /// </summary>
323 /// <returns></returns>
324 public virtual bool Save()
325 {
326 return Save(true);
327 }
328
329 /**//// <summary>
330 /// 将当前实例保存到T.ConfigFileName指定的配置文件
331 /// </summary>
332 /// <param name="Tobj"></param>
333 /// <param name="BackupOnError"></param>
334 /// <returns></returns>
335 public bool Save(T Tobj, bool BackupOnError)
336 {
337 return SaveAs(Tobj, ConfigFileFullName, BackupOnError);
338 }
339
340 /**//// <summary>
341 /// 将一个实例对象保存到FileFullName指定的配置文件
342 /// </summary>
343 /// <param name="FileFullName"></param>
344 /// <param name="Tobj"></param>
345 /// <param name="BackupOnError"></param>
346 /// <returns></returns>
347 protected bool SaveAs(T Tobj, string FileFullName, bool BackupOnError)
348 {
349 lock (typeof(T))
350 {
351 if (Tobj == default(T))
352 {
353 Exception = new Exception(typeof(T).FullName + " 未正确实现 Current;");
354 return false;
355 }
356 FileStream fs = null;
357 FileInfo fi = new FileInfo(FileFullName);
358 string BackupFilePath = null;
359
360 if (BackupOnError)
361 {
362 backup#region backup
363
364 BackupFilePath = fi.FullName + ".Save." + DateTime.Now.ToString("yyMMddHHssfff") + ".bak";
365 try
366 {
367 //如果存在先备份
368 if (fi.Exists)
369 {
370 fi.CopyTo(BackupFilePath, true);
371 }
372 else if (!fi.Directory.Exists)
373 {
374 //目录不存在创建目录
375 fi.Directory.Create();
376 }
377 }
378 catch (Exception ex)
379 {
380 Tobj.Exception = new Exception("备份配置文件时发生错误!", ex);
381 return false;
382 }
383 #endregion
384 }
385
386 try
387 {
388 if (fi.Exists)
389 fi.Delete();
390 serialize it#region serialize it
391 fs = new FileStream(fi.FullName, FileMode.Create, FileAccess.Write, FileShare.Read);
392 IFormatter formatter = null;
393 switch (CurrentFormatter)
394 {
395 case Formatter.Binary:
396 formatter = new BinaryFormatter();
397 formatter.Serialize(fs, Tobj);
398 break;
399 case Formatter.SoapXml:
400 formatter = new SoapFormatter();
401 formatter.Serialize(fs, Tobj);
402 break;
403 case Formatter.Xml:
404 XmlSerializer serializer = new XmlSerializer(typeof(T));
405
406 serializer.Serialize(fs, Tobj);
407 break;
408 default:
409 break;
410 }
411 #endregion
412
413 //成功则删除当前备份
414
415 成功则删除当前备份#region 成功则删除当前备份
416 if (BackupOnError)
417 try
418 {
419 File.Delete(BackupFilePath);
420 }
421 catch (Exception ex)
422 {
423 Tobj.Exception = new Exception("删除备份文件时发生错误!", ex);
424 }
425 #endregion
426
427 return true;
428 }
429 catch (Exception ex)
430 {
431#if txtLog
432 Log.WriteLog(ex);
433#endif
434 Tobj.Exception = new Exception("保存配置文件时发生错误!", ex);
435
436 return false;
437 }
438 finally
439 {
440 if (fs != null)
441 fs.Close();
442 }
443 }
444 }
445 #endregion
446
447 删除配置文件#region 删除配置文件
448 /**//// <summary>
449 /// 删除配置文件
450 /// </summary>
451 /// <returns></returns>
452 public bool Delete()
453 {
454 return Delete(ConfigFileFullName);
455 }
456 /**//// <summary>
457 /// 删除指定的配置文件 .文件不存在不引发异常。并返回true
458 /// </summary>
459 /// <param name="FileFullName"></param>
460 /// <returns></returns>
461 public bool Delete(string FileFullName)
462 {
463 try
464 {
465 if (File.Exists(FileFullName))
466 File.Delete(FileFullName);
467 return true;
468 }
469 catch (Exception ex)
470 {
471 Current.Exception = ex;
472 return false;
473 }
474 }
475 #endregion
476
477 抽象成员#region 抽象成员
478 /**//// <summary>
479 /// 返回派生类的当前实例
480 /// protected override T Current
481 /// {
482 /// get
483 /// {
484 /// return this;
485 /// }
486 /// }
487 /// </summary>
488 protected abstract T Current
489 {
490 get;
491 }
492 /**//// <summary>
493 /// 自定义初始化配置类
494 /// 获取 T 的配置实例时,如果配置文件不存在或者读取失败时返回此实例
495 /// 重写中一般读取备份的配置文件,必须保证备份配置文件存在,否则发生异常。
496 /// 默认返回 new T();
497 /// </summary>
498 /// <returns></returns>
499 protected virtual T CustomizingInit()
500 {
501 return Current;
502 }
503 /**//// <summary>
504 /// 配置文件名
505 /// <c>配置文件名</c>
506 /// <example>
507 /// 配置文件名
508 /// </example>
509 /// </summary>
510 private string ___file = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "Config/" + typeof(T).Name + ".cfg");
511 /**//// <summary>
512 /// 配置文件全路径名
513 /// 默认:winform 在应用程序目录;web应用程序默认bin目录。
514 /// </summary>
515 [XmlIgnore]
516 public virtual string ConfigFileFullName
517 {
518 get
519 {
520 return ___file;
521 }
522 set
523 {
524 ___file = value;
525 }
526 }
527 #endregion
528 }
529}
530
2#define txtLogAll
3
4using System;
5using System.Web;
6using System.Xml.Serialization;
7using System.IO;
8using System.Runtime.Serialization;
9using System.Runtime.Serialization.Formatters.Soap;
10using System.Runtime.Serialization.Formatters.Binary;
11using System.Web.Caching;
12using System.Threading;
13using tjb.Utility.Caching;
14using System.Xml;
15using System.Text;
16
17
18namespace tjb.Utility.Config
19{
20
21 文件序列化的类型#region 文件序列化的类型
22 /**//// <summary>
23 /// 序列化文件的方式
24 /// Binary,Xml,SoapXml
25 /// </summary>
26 public enum Formatter
27 {
28 /**//// <summary>
29 /// 字节
30 /// </summary>
31 Binary,
32 /**//// <summary>
33 /// xml
34 /// </summary>
35 Xml,
36 /**//// <summary>
37 /// soap协议的xml
38 /// </summary>
39 SoapXml
40 }
41 #endregion
42
43 /**//// <summary>
44 /// 序列化基类 by Tjb 2007/06
45 /// T 类型不能创建多态的多个实例
46 /// 优化和修正,增加配置文件备份 2008/9/18
47 /// 修改:获取实例时加锁
48 /// 修改:
49 /// SaveAs(T Tobj, string FileFullName, bool BackupOnError) 方法增加线程锁定。防止多线程冲突 2008/10/24
50 /// </summary>
51 /// <typeparam name="T">T 必须有无参数的构造函数</typeparam>
52 [Serializable]
53 public abstract class IConfig<T> where T : IConfig<T>, new()
54 {
55
56 Exceptions#region Exceptions
57 private Exception __ConfigException;
58 /**//// <summary>
59 /// 读取或保存时发生的错误
60 /// </summary>
61 [XmlIgnore, SoapIgnore]
62 public Exception Exception
63 {
64 get
65 {
66 return __ConfigException;
67 }
68 private set
69 {
70 if (value != null)
71 {
72 HasError = true;
73 __ConfigException = value;
74#if txtLogAll
75 Log.WriteLog(value);
76#endif
77 }
78 }
79 }
80 private bool __HasError = false;
81 /**//// <summary>
82 /// 获取一个值 指示读取或者保存时是否发生错误
83 /// 如果当前错误被获取后,此标志将被置为false
84 /// </summary>
85 [XmlIgnore, SoapIgnore]
86 public bool HasError
87 {
88 get { return __HasError; }
89 private set { __HasError = value; }
90 }
91 #endregion
92
93 序列化类型 可重写#region 序列化类型 可重写
94
95 private Formatter _CurrentFormatter = Formatter.Xml;
96 /**//// <summary>
97 /// 序列化的方式
98 /// </summary>
99 [XmlIgnore]
100 protected virtual Formatter CurrentFormatter
101 {
102 get
103 {
104 return _CurrentFormatter;
105 }
106 set
107 {
108 _CurrentFormatter = value;
109 }
110 }
111
112 #endregion
113
114 获取单个实例#region 获取单个实例
115
116 /**//// <summary>
117 /// 获取Cache中缓存T的key
118 /// </summary>
119 public static string CacheKEY
120 {
121 get
122 {
123 // return typeof(T).GUID.ToString("N");
124 return typeof(T).FullName;
125 }
126 }
127 /**//// <summary>
128 /// 从缓存(缓存KEY为T的命空间加类名)获取当前类的实例,如果缓存不存在则读取文件(ConfigFileFullName), 并缓存。
129 /// </summary>
130 public static T Instance
131 {
132 get
133 {
134 T c = CacheUtility.Get<T>(CacheKEY);
135 if (c == null)
136 {
137 //这中方式无异于不加锁
138 //object Monitor = new object();
139 //lock (Monitor)
140 lock (typeof(T))
141 {
142 c = CacheUtility.Get<T>(CacheKEY);
143 if (c == null)
144 {
145 c = new T().Read();
146#if DEBUG
147 CacheUtility.SetSlidingExpiration(CacheKEY, c, c.ConfigFileFullName, 7, CacheItemPriority.NotRemovable, new CacheItemRemovedCallback(CallR));
148#else
149 CacheUtility.SetSlidingExpiration(CacheKEY, c, c.ConfigFileFullName, 7, CacheItemPriority.NotRemovable, null);
150#endif
151 }
152 }
153 }
154 return c;
155 }
156 }
157
158 #endregion
159
160 Caching..#region Caching..
161
162 /**//// <summary>
163 /// 从ConfigFileName指定文件以CurrentSerializeType读取实例,如果存在缓存则移除并重新进行缓存
164 /// 如果不存在则以InitConfig初始化类,创建并保存文件
165 /// </summary>
166 /// <returns></returns>
167 protected T ResetCacheAndRead()
168 {
169 ResetCache();
170 return Read();
171 }
172 /**//// <summary>
173 /// 移除CacheKEY 缓存
174 /// </summary>
175 public void ResetCache()
176 {
177 HttpRuntime.Cache.Remove(CacheKEY);
178 }
179 #endregion
180
181 获取#region 获取
182
183 /**//// <summary>
184 /// 读取缓存中的实例如果不存在则
185 /// 从ConfigFileName指定文件以CurrentSerializeType读取实例
186 /// 如果不存在则以InitConfig初始化类,创建并保存文件
187 /// </summary>
188 /// <returns></returns>
189 virtual protected T Read()
190 {
191 return Read(ConfigFileFullName, true, CurrentFormatter);
192 }
193
194 /**//// <summary>
195 /// 从ConfigFileName指定文件以CurrentSerializeType读取实例
196 /// 如果不存在则以InitConfig初始化类,创建并保存文件
197 /// </summary>
198 /// <param name="configFileFullName">缓存文件绝对路径</param>
199 /// <param name="serializeType"></param>
200 /// <param name="BackupOnError">读取错误时是否备份</param>
201 /// <returns></returns>
202 protected T Read(string configFileFullName, bool BackupOnError, Formatter serializeType)
203 {
204 T t = CacheUtility.Get<T>(CacheKEY);
205 if (t != null)
206 return t;
207 FileInfo fi = new FileInfo(configFileFullName);
208 if (fi.Exists)
209 {
210
211 FileStream fs = null;
212 try
213 {
214 open the stream#region open the stream
215 // open the stream
216 fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
217 IFormatter formatter = null;
218 switch (serializeType)
219 {
220 case Formatter.Binary:
221 formatter = new BinaryFormatter();
222 t = formatter.Deserialize(fs) as T;
223 break;
224 case Formatter.SoapXml:
225 formatter = new SoapFormatter();
226 t = formatter.Deserialize(fs) as T;
227 break;
228 case Formatter.Xml:
229 XmlSerializer serializer = new XmlSerializer(typeof(T));
230 t = serializer.Deserialize(fs) as T;
231 break;
232 default:
233 break;
234 }
235 #endregion
236
237 if (fs != null)
238 fs.Close();
239 }
240 catch (Exception ex)
241 {
242 if (fs != null)
243 fs.Close();
244 t = CustomizingInit();
245
246 读取失败 进行备份 防止以后使用默认配置覆盖当前数据#region 读取失败 进行备份 防止以后使用默认配置覆盖当前数据
247 if (BackupOnError)
248 if (fi.Exists)
249 {
250 string BackupFilePath = fi.FullName + ".Read." + DateTime.Now.ToString("yyMMddHHssfff") + ".bak";
251 try
252 {
253 fi.CopyTo(BackupFilePath, true);
254 t.Save(true);
255 }
256 catch (Exception ioex)
257 {
258 t.Exception = new Exception("读取配置文件出错后,对配置文件进行备份发生错误!", ioex);
259 }
260 }
261 #endregion
262
263 t.Exception = new Exception("读取配置文件时发生错误!将返回CustomizingInit()方法的实例,默认为 new T()!", ex);
264 }
265 finally
266 {
267
268 }
269 }
270 else
271 {
272 t = CustomizingInit();
273
274 //不存在的同一文件不能读多次
275 //防止在CustomizingInit()方法中调用Read(string configFileName, SerializeType serializeType) 造成死循环
276 string ProtectedKEY = Thread.CurrentThread.ManagedThreadId + fi.FullName + "init";
277 if (CacheUtility.GetAnyType<bool>(ProtectedKEY) == false)
278 {
279 CacheUtility.SetAbsoluteExpiration(ProtectedKEY, true, null, 0.02);
280 }
281 else
282 {
283 CacheUtility.Remove(ProtectedKEY);
284 throw new Exception("'" + fi.FullName + "' 文件不存在!读取过于频繁。导致此保护异常发生。");
285 }
286 t.Exception = new Exception("配置文件:'" + fi.FullName + "' 不存在!默认返回CustomizingInit()方法返回的实例。");
287 }
288 if (t == null)
289 t.Exception = new Exception("发生错误,请检查初始化配置方法 CustomizingInit() 未返回的配置实例不能为空,或者系统中存在缓存 key :" + CacheKEY);
290 return t;
291 }
292
293#if DEBUG
294 private static void CallR(string key, object obj, CacheItemRemovedReason re)
295 {
296#if txtLogAll
297 Log.WriteLog(key + "::::" + re.ToString());
298#endif
299 }
300#endif
301
302 #endregion
303
304 保存#region 保存
305 /**//// <summary>
306 /// 将当前实例进行保存
307 /// </summary>
308 /// <param name="BackupOnError">发生错误时是否备份</param>
309 /// <returns></returns>
310 public bool Save(bool BackupOnError)
311 {
312 if (Current == null)
313 {
314 Exception = new Exception(typeof(T).FullName + " 未正确实现 Current;");
315 return false;
316 }
317 return Save(Current, BackupOnError);
318 }
319 /**//// <summary>
320 /// 将当前实例进行保存
321 /// 发生错误时将备份配置文件
322 /// </summary>
323 /// <returns></returns>
324 public virtual bool Save()
325 {
326 return Save(true);
327 }
328
329 /**//// <summary>
330 /// 将当前实例保存到T.ConfigFileName指定的配置文件
331 /// </summary>
332 /// <param name="Tobj"></param>
333 /// <param name="BackupOnError"></param>
334 /// <returns></returns>
335 public bool Save(T Tobj, bool BackupOnError)
336 {
337 return SaveAs(Tobj, ConfigFileFullName, BackupOnError);
338 }
339
340 /**//// <summary>
341 /// 将一个实例对象保存到FileFullName指定的配置文件
342 /// </summary>
343 /// <param name="FileFullName"></param>
344 /// <param name="Tobj"></param>
345 /// <param name="BackupOnError"></param>
346 /// <returns></returns>
347 protected bool SaveAs(T Tobj, string FileFullName, bool BackupOnError)
348 {
349 lock (typeof(T))
350 {
351 if (Tobj == default(T))
352 {
353 Exception = new Exception(typeof(T).FullName + " 未正确实现 Current;");
354 return false;
355 }
356 FileStream fs = null;
357 FileInfo fi = new FileInfo(FileFullName);
358 string BackupFilePath = null;
359
360 if (BackupOnError)
361 {
362 backup#region backup
363
364 BackupFilePath = fi.FullName + ".Save." + DateTime.Now.ToString("yyMMddHHssfff") + ".bak";
365 try
366 {
367 //如果存在先备份
368 if (fi.Exists)
369 {
370 fi.CopyTo(BackupFilePath, true);
371 }
372 else if (!fi.Directory.Exists)
373 {
374 //目录不存在创建目录
375 fi.Directory.Create();
376 }
377 }
378 catch (Exception ex)
379 {
380 Tobj.Exception = new Exception("备份配置文件时发生错误!", ex);
381 return false;
382 }
383 #endregion
384 }
385
386 try
387 {
388 if (fi.Exists)
389 fi.Delete();
390 serialize it#region serialize it
391 fs = new FileStream(fi.FullName, FileMode.Create, FileAccess.Write, FileShare.Read);
392 IFormatter formatter = null;
393 switch (CurrentFormatter)
394 {
395 case Formatter.Binary:
396 formatter = new BinaryFormatter();
397 formatter.Serialize(fs, Tobj);
398 break;
399 case Formatter.SoapXml:
400 formatter = new SoapFormatter();
401 formatter.Serialize(fs, Tobj);
402 break;
403 case Formatter.Xml:
404 XmlSerializer serializer = new XmlSerializer(typeof(T));
405
406 serializer.Serialize(fs, Tobj);
407 break;
408 default:
409 break;
410 }
411 #endregion
412
413 //成功则删除当前备份
414
415 成功则删除当前备份#region 成功则删除当前备份
416 if (BackupOnError)
417 try
418 {
419 File.Delete(BackupFilePath);
420 }
421 catch (Exception ex)
422 {
423 Tobj.Exception = new Exception("删除备份文件时发生错误!", ex);
424 }
425 #endregion
426
427 return true;
428 }
429 catch (Exception ex)
430 {
431#if txtLog
432 Log.WriteLog(ex);
433#endif
434 Tobj.Exception = new Exception("保存配置文件时发生错误!", ex);
435
436 return false;
437 }
438 finally
439 {
440 if (fs != null)
441 fs.Close();
442 }
443 }
444 }
445 #endregion
446
447 删除配置文件#region 删除配置文件
448 /**//// <summary>
449 /// 删除配置文件
450 /// </summary>
451 /// <returns></returns>
452 public bool Delete()
453 {
454 return Delete(ConfigFileFullName);
455 }
456 /**//// <summary>
457 /// 删除指定的配置文件 .文件不存在不引发异常。并返回true
458 /// </summary>
459 /// <param name="FileFullName"></param>
460 /// <returns></returns>
461 public bool Delete(string FileFullName)
462 {
463 try
464 {
465 if (File.Exists(FileFullName))
466 File.Delete(FileFullName);
467 return true;
468 }
469 catch (Exception ex)
470 {
471 Current.Exception = ex;
472 return false;
473 }
474 }
475 #endregion
476
477 抽象成员#region 抽象成员
478 /**//// <summary>
479 /// 返回派生类的当前实例
480 /// protected override T Current
481 /// {
482 /// get
483 /// {
484 /// return this;
485 /// }
486 /// }
487 /// </summary>
488 protected abstract T Current
489 {
490 get;
491 }
492 /**//// <summary>
493 /// 自定义初始化配置类
494 /// 获取 T 的配置实例时,如果配置文件不存在或者读取失败时返回此实例
495 /// 重写中一般读取备份的配置文件,必须保证备份配置文件存在,否则发生异常。
496 /// 默认返回 new T();
497 /// </summary>
498 /// <returns></returns>
499 protected virtual T CustomizingInit()
500 {
501 return Current;
502 }
503 /**//// <summary>
504 /// 配置文件名
505 /// <c>配置文件名</c>
506 /// <example>
507 /// 配置文件名
508 /// </example>
509 /// </summary>
510 private string ___file = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "Config/" + typeof(T).Name + ".cfg");
511 /**//// <summary>
512 /// 配置文件全路径名
513 /// 默认:winform 在应用程序目录;web应用程序默认bin目录。
514 /// </summary>
515 [XmlIgnore]
516 public virtual string ConfigFileFullName
517 {
518 get
519 {
520 return ___file;
521 }
522 set
523 {
524 ___file = value;
525 }
526 }
527 #endregion
528 }
529}
530