Coding with .NET

Live with passion, coding with passion....

首页 新随笔 联系 订阅 管理

在配置我们的应用程序的时候,经常会遇到有的配置元素、配置节需要可变的属性。比如,在 .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  阅读(1376)  评论(2)    收藏  举报