昨天基本弄清config的使用之后,再看WP的API,暈了。結果WP不支持system.configuration命名空間,這意味著想在WP上用App.config不大可能了。
WP具體支持API請查看
.net WP API
API reference
不過還是記錄下App.config的使用。
有很大部分是從MSDN學來的,如果有人看我的這篇文章的話可以先去看看MSDN的相關章節 http://msdn.microsoft.com/en-us/library/system.configuration.configuration(v=vs.110).aspx
這個比較簡單,也有很多資料講到,在我的C:/Windows/Microsoft.NET/Framework/v4.0.30319/Config中,有machine.config這個文件
有下面節選
1 <configuration>2 <configSections>3 <section name="appSettings" type="System.Configuration.AppSettingsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" restartOnExternalChanges="false" requirePermission="false"/>4 <section name="connectionStrings" type="System.Configuration.ConnectionStringsSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" requirePermission="false"/>
后面長串省略………………
所以appSettings是一個section,當在配置文件中輸入 <appSettings>節點時,系統會幫我們映射到System.Configuration.AppSettingsSection這個類中去,用reflector看看這個類
繼承自ConfigurationSection
1 PRivate static volatile ConfigurationProperty s_propAppSettings;2 private static volatile ConfigurationProperty s_propFile;
其跟App.config中映射的字段
1 ConfigurationProperty property = new ConfigurationProperty(null, typeof(KeyValueConfigurationCollection), null, ConfigurationPropertyOptions.IsDefaultCollection);2 ConfigurationProperty property2 = new ConfigurationProperty("file", typeof(string), string.Empty, ConfigurationPropertyOptions.None);
1 s_propAppSettings = property;
2 s_propFile = property2;
屬性暴露出來為:
file(attribute)
不作為元素:
1 [ConfigurationProperty("file", DefaultValue="")] 2 public string File 3 { 4 get 5 { 6 string str = (string) base[s_propFile]; 7 if (str == null) 8 { 9 return string.Empty;10 }11 return str;12 }13 set14 {15 base[s_propFile] = value;16 }17 }
element:
1 [ConfigurationProperty("", IsDefaultCollection=true)]2 public KeyValueConfigurationCollection Settings3 {4 get5 {6 return (KeyValueConfigurationCollection) base[s_propAppSettings];7 }8 }
對于不是嵌套的element,而是直接作為section的子節點集合,就照這樣寫,這樣寫沒有在App.config的對應名字,看起來全是add元素(當然也可以有,后面會說明)
再來看看KeyValueConfigurationCollection這個集合繼承自ConfigurationElementCollection
其中重要的兩個方法:
1 protected override ConfigurationElement CreateNewElement()2 {3 return new KeyValueConfigurationElement();4 }5 6 protected override object GetElementKey(ConfigurationElement element)7 {8 return ((KeyValueConfigurationElement) element).Key;9 }
所以其實在每個Add中,Add的是KeyValueConfigurationElement,這個類的Key屬性作為集合的關鍵字,再來看看KeyValueConfigurationElement類,這個類繼承自ConfigurationElement
關鍵部分:
1 private static readonly ConfigurationProperty _propKey = new ConfigurationProperty("key", typeof(string), string.Empty, ConfigurationPropertyOptions.IsKey | Configurat ionPropertyOptions.IsRequired); 2 private static readonly ConfigurationProperty _propValue = new ConfigurationProperty("value", typeof(string), string.Empty, ConfigurationPropertyOptions.None);
3 [ConfigurationProperty("key", Options=ConfigurationPropertyOptions.IsKey, DefaultValue="")] 4 public string Key 5 { 6 get 7 { 8 return (string) base[_propKey]; 9 }10 }11 [ConfigurationProperty("value", DefaultValue="")]12 public string Value13 {14 get15 {16 return (string) base[_propValue];17 }18 set19 {20 base[_propValue] = value;21 }22 }
具體到element的key,value了。這樣我們也可以自定義節點了。
創建一個控制臺應用和一個類庫,在控制臺中先添加system.configuration程序集的引用。然后我們寫上自己想要的App.config的內容。如下
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 8 <Songs ChannelId="1"> 9 <add name="1.mp3" length="100" />10 <add name="2.mp3" length="100" />11 <add name="3.mp3"/>12 <add length="200"/>13 </Songs>14 15 </configuration>
這樣算是定義好了一些配置,其中有些song配置使用了默認的值。
但是為了使Songs這個Section工作起來,我們也需要像Appsettings一樣添加自定義Section,我們添加 <configSections>元素,再在里面添加Section,添加好,完整如下
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <configSections> 7 <section name="Songs" type="ConfigLib.SongsSection,ConfigLib"/> 8 </configSections> 9 10 <Songs ChannelId="1">11 <add name="1.mp3" length="100" />12 <add name="2.mp3" length="100" />13 <add name="3.mp3"/>14 <addlength="200"/>15 </Songs>16 17 </configuration>
其中ConfigLib為我們一開始添加的庫的名字 ConfigLib.SongsSection為要映射到的類。
接下看看SongsSection類。
同樣在ConfigLib這個Lib中添加system.configuration這個dll,然后使SongsSection這個類去繼承ConfigurationSection類
1 namespace ConfigLib2 {3 public class SongsSection:ConfigurationSection4 {5 }6 }
由于我們的appSettings的子節點都是數據的單個點,總共是一個集合,所以我們還要一個集合類用來存放所有的song.這個集合要繼承ConfigurationElementCollection類
1 namespace ConfigLib2 {3 class Songcollection:ConfigurationElementCollection4 {5 }6 }
但是這樣是編譯不過的,因為ConfigurationElementCollection類里有2個標注為abstract的方法需要我們子類來實現,先讓它編譯通過,如下
1 public class Songcollection:ConfigurationElementCollection 2 { 3 protected override ConfigurationElement CreateNewElement() 4 { 5 throw new NotImplementedException(); 6 } 7 protected override object GetElementKey(ConfigurationElement element) 8 { 9 throw new NotImplementedException();10 }11 }
先不管實現,我們用這個Collection來裝song.回到SongsSection類,我們可以使用上面的集合了,像appSettings那樣,但要注意,我們為Songs這個Section添加了類似XML中屬性(attribute)的channleid,由于這個不是Element,是個int類型(后面還有ConfigurationElement類),所以我們在類中屬性(Property)中使用的時候這個的時候不會跑到element中去,它會乖乖在XML的屬性位置。代碼如下
1 namespace ConfigLib 2 { 3 public class SongsSection:ConfigurationSection 4 { 5 private readonly ConfigurationProperty collectionproperty = new ConfigurationProperty(null, typeof(Songcollection), null, ConfigurationPropertyOptions.IsDefaultCollection); 6 [ConfigurationProperty("",IsDefaultCollection=true)] 7 public Songcollection SongCollection 8 { 9 get10 {11 return (Songcollection)this[collectionproperty];12 13 }14 }15 [ConfigurationProperty("ChannelId", IsKey = false, DefaultValue = "-1")]16 public int ChannelId17 {18 get19 {20 return (int)this["ChannelId"];21 }22 }23 }24 }
其中SongCollection屬性的寫法很像appSettings的寫法。
接下來看看Songcollection這個集合類最簡單的寫法:
1 namespace ConfigLib 2 { 3 public class Songcollection:ConfigurationElementCollection 4 { 5 protected override ConfigurationElement CreateNewElement() 6 { 7 return new SongElement(); 8 } 9 protected override object GetElementKey(ConfigurationElement element)10 {11 return ((SongElement)element).Name;12 }13 14 }15 }
集合類的很多屬性我們使用父類的,字面意思都比較好理解,其中GetElementKey是為這個集合指定關鍵字的,有點像數據庫中的Key,這個Key不能重復,并且我們可以通過
這個Key獲得集合中的元素(SongElement).
集合中主要是Element,Element基本就和XML中Element一樣,SongElement這個類如下,用這個類(SongElement)定義的變量就是(app.config)XML中的Element,而不是Attribute,(類中的所有簡單類型都在Attribute中出現)
1 namespace ConfigLib 2 { 3 public class SongElement:ConfigurationElement 4 { 5 [ConfigurationProperty("name",IsKey=true,DefaultValue="default.mp3")] 6 public string Name 7 { 8 get 9 {10 return (string)this["name"];11 }12 }13 [ConfigurationProperty("length", IsKey = false, DefaultValue = "-1")]14 public int Length15 {16 get17 {18 return (int)this["length"];19 }20 }21 }22 }
為每個XML的attribute設置默認值,并且不為必須的,寫App.config的時候保證Key(這里是歌的名字)不重復,如果需要通過索引訪問song的集合,在集合中加如下索引器:
1 public SongElement this[int index]2 {3 get 4 {5 return (SongElement)BaseGet(index);6 }7 }
由于集合是默認的AddClear類型,所以我們的XML元素(element)雖然存在,但是要寫成add,clear形式,(如果有clear,clear寫在哪,那么之前add過的元素就都不見了)
代碼下載
App.config還可以改成下面這樣
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <configSections> 4 <section name="Songs" type="ConfigLib.SongsSection,ConfigLib"/> 5 </configSections> 6 <Songs ChannelId="1"> 7 <song name="1.mp3" length="100" /> 8 <song name="2.mp3" length="100" /> 9 <song name="3.mp3"/>10 <song length="200"/>11 </Songs>12 </configuration>
把add改成了song,這樣順眼一點
那僅僅只要在集合類中添加:
1 protected override string ElementName 2 { 3 get 4 { 5 return "song"; 6 } 7 } 8 public override ConfigurationElementCollectionType CollectionType 9 {10 get11 {12 return ConfigurationElementCollectionType.BasicMap;13 }14 }
就可以了
如果App.config改為下面這樣:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <configSections> 4 <section name="Songs" type="ConfigLib.SongsSection,ConfigLib"/> 5 </configSections> 6 <Songs ChannelId="1"> 7 <special_special_song specialsongname="special_1.mp3"/> 8 <specialsongs> 9 <specialsong specialsongname="special_2.mp3"/>10 <specialsong specialsongname="special_3.mp3"/>11 <specialsong specialsongname="special_4.mp3"/>12 </specialsongs>13 <song name="1.mp3" length="100" />14 <song name="2.mp3" length="100" />15 <song name="3.mp3"/>16 <song length="200"/>17 </Songs>18 </configuration>
一樣的道理,加一個SpecialSongElement類和容納這個類的集合SpecialSongCollection,然后再在Section中做添加即可,在section類中,第一個
<special_special_song specialsongname="special_1.mp3"/>對應:
1 [ConfigurationProperty("special_special_song", IsKey = false)]2 public SpecialSongElement SpecialSong3 {4 get5 {6 return (SpecialSongElement)this["special_special_song"];7 }8 }
而集合
<specialsongs>對應:
1 [ConfigurationProperty("specialsongs", IsKey = false, IsDefaultCollection = false)]2 public SpecialSongCollection SpecialSongs3 {4 get5 {6 return (SpecialSongCollection)this["specialsongs"];7 }8 }
注意IsDefaultCollection = false。這個SpecialSongCollection集合跟前面的集合基本一樣。
最后的效果:
代碼下載
如果有多個Section的時候可以考慮使用sectionGroup來給各個Section分組
像系統的C:/Windows/Microsoft.NET/Framework/v4.0.30319/Config/machine.config一樣
還有雖然微軟不提倡使用IConfigurationSectionHandler來解析Section,但是我覺得這個方法知道也不錯,這個解析方法是把getsection中的section作為根XmlNode,傳到接口實現的方法 public object Create(object parent, object configContext, System.Xml.XmlNode section)中
其中System.Xml.XmlNode section參數就是根xmlNode,然后就可以操作Xml了。
新聞熱點
疑難解答