Coding with .NET

Live with passion, coding with passion....

首页 新随笔 联系 订阅 管理
  16 Posts :: 3 Stories :: 118 Comments :: 0 Trackbacks

在配置我们的应用程序的时候,经常会遇到有的配置元素、配置节需要可变的属性。比如,在 .net 2.0 中经常遇到的 Provider 模式。在配置 Provider 的时候,可能会需要为不同的 Provider 提供不同的属性,比如为 SqlDataProvider 提供连接字符串属性,为 XmlFileDataProvider 提供文件路径等。

下面代码是一般的 ConfigurationElement 需要的代码:

 1public class ProviderSettings : ConfigurationElement
 2{
 3  private static readonly ConfigurationProperty _propName;
 4  private static readonly ConfigurationProperty _propType;
 5  private static readonly ConfigurationPropertyCollection _props;
 6
 7  static ProviderSettings()
 8  {
 9    _propName = new ConfigurationProperty("name"typeof(string), null, ConfigurationPropertyOptions.IsKey | ConfigurationPropertyOptions.Required);
10    _propType = new ConfigurationProperty("type"typeof(string), nullnullnew StringValidator(1, Int32.MaxValue), ConfigurationPropertyOptions.Required);
11
12    _props = new ConfigurationPropertyCollection();
13    _props.Add(_propName);
14    _props.Add(_propType);
15  }

16  
17  protected override ConfigurationPropertyCollection Properties
18  {
19    get return _props; }
20  }

21
22  [ConfigurationProperty("name", RequiredValue = true, Options = ConfigurationPropertyOptions.IsKey)]
23  [StringValidator(MinLength = 1)]
24  public string Name
25  {
26    get return (string)base[_propName]; }
27    set base[_propName] = value; }
28  }

29
30  [ConfigurationProperty("type", RequiredValue = true)]
31  [StringValidator(MinLength = 1)]
32  public string Type
33  {
34    get return (string)base[_propType]; }
35    set base[_propType] = value; }
36  }

37}

为了使 .net 2.0 配置系统允许我们使用自定义的属性(也就是除了已经定义的 name 和 type 属性),我们还需要做一些其他的工作。再看看 ConfigurationElement 的方法和属性,发现有 virtual 的 OnDeserializeUnrecognizedAttributeOnDeserializeUnrecognizedElement 方法:

  • OnDeserializeUnrecognizedAttribute: Called when an unknown attribute is encountered while deserializing the ConfigurationElement object
  • OnDeserializeUnrecognizedElement: Called when an unknown sub element is encountered while deserializing the ConfigurationElement object
说的再明白不过了,就是允许我们自己处理配置系统不认识的属性(就是除开已经定义的 name 和 type 属性)和子元素(我们这里讨论属性,子元素就先放在一边吧)。既然可以这样,我们就在 OnDeserializeUnrecognizedAttribute 方法里面将不认识的属性放到一个地方不就可以了吗。那再把上面的代码改一改。
 1public ProviderSettings : ConfigurationElement
 2{
 3  // Other members
 4  .
 5
 6  private Dictionary<stringstring> _params = new Dictionary<stringstring>(StringComparer.InvariantCulture);
 7  
 8  /// <summary>
 9  /// All the undefined attributes.
10  /// </summary>

11  public Dictionary<stringstring> Parameters
12  {
13    get return _params; }
14  }

15  
16  protected override bool OnDeserializeUnrecognizedAttribute(string name, string value)
17  {
18    Parameters[name] = value;
19    return true;
20  }

21}

其对应的单元测试代码就不写了,大家自己写吧:)

完成了上面的步骤,其实还是不够的。如果单元测试代码写的好的话,马上就能发现问题了:) 使用上面的方法,在读取配置的时候是没有问题的,可以顺利得从 Parameters 中获取配置的数据。然而在保存的时候就出现问题了。在使用配置的时候,我们在应用程序无论怎么操作 Parameters,保存的时候都不能将改动保存到配置文件中;而且如果 ProviderSettings 中的已定义属性被更改过的话,在保存的时候那些 unrecognized attributes 也消失了。也就是我们只能从配置文件中读取属性而不能修改这些属性!这显然不满足我们的需求!不过从刚才的现象中似乎表示被保存的配置应该都是 Configuration.Properties 中的内容。看来我们还要想办法把那些 unrecognized attributes 放到 Properties 中才行啊。

下面就是改进以后的代码:

 1public ProviderSettings : ConfigurationElement
 2{
 3  // Other members
 4  //
 5  // Note: Since _props will be updated in IsModified-UpdatePropertyCollection,
 6  // it cannot be static. And also, the static constructor will be modified.
 7  .
 8  
 9  private readonly ConfigurationPropertyCollection _props;
10  private static readonly PredefinedAttributes = new string[]"name","type" };
11  
12  public ProviderSettings()
13  {
14    _props = new ConfigurationPropertyCollection();
15    _props.Add(_propName);
16    _props.Add(_propType);
17  }

18  
19  protected override bool IsModified()
20  {
21    return (!UpdatePropertyCollection()) ? base.IsModified() : true;
22  }

23  
24  private bool UpdatePropertyCollection()
25  {
26    bool isModified = false;
27
28    List props = new List();
29    foreach (ConfigurationProperty prop in Properties) {
30      if (Array.BinarySearch(PredefinedAttributes, prop.Name) >= 0 ||
31        parameters.ContainsKey(prop.Name)) {
32        continue;
33      }

34
35      props.Add(prop.Name);
36      isModified = true;
37    }

38
39    foreach (string name in props) {
40      Properties.Remove(name);
41    }

42
43    foreach (KeyValuePair kvp in Parameters) {
44      string t = GetProperty(kvp.Key);
45      if (t == null || kvp.Value != t) {
46        SetProperty(kvp.Key, kvp.Value);
47        isModified = true;
48      }

49    }

50
51    return isModified;
52  }

53
54  private bool SetProperty(string name, string value)
55  {
56    ConfigurationProperty prop = null;
57    if (Properties.Contains(name)) {
58      prop = Properties[name];
59    }

60    else {
61      prop = new ConfigurationProperty(name, typeof(string), null);
62      Properties.Add(prop);
63    }

64
65    if (prop != null{
66      base[prop] = value;
67      return true;
68    }

69    else {
70      return false;
71    }

72  }

73
74  private string GetProperty(string name)
75  {
76    if (Properties.Contains(name)) {
77      ConfigurationProperty prop = Properties[name];
78      if (prop != null{
79        return base[prop] as string;
80      }

81    }

82
83    return null;
84  }

85}
posted on 2005-09-02 11:52 Lin 阅读(988) 评论(2)  编辑 收藏 网摘 所属分类: .Net

Feedback

#1楼  2005-09-02 11:57 dudu      
为什么要将同一篇文章发表在.NET 2.0专题的多个分类中?
  回复  引用  查看    

#2楼  2005-09-02 12:45 Lin      
不可以吗?那是复选框吧
我觉得它可以分开多个不同的分类吧
  回复  引用  查看    





标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
Google站内搜索

China-pub 计算机图书网上专卖店!6.5万品种 2-8折!
近千种 9-95 新二手计算图书火热销售中!
开发者征途系统新作:《设计模式——基于C#的工程化实现及扩展》

相关文章:

相关链接: