2 // System.Configuration.ConfigurationElementCollection.cs
5 // Tim Coleman (tim@timcoleman.com)
7 // Copyright (C) Tim Coleman, 2004
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
34 using System.Collections;
35 using System.Diagnostics;
38 namespace System.Configuration
40 [DebuggerDisplayAttribute ("Count = {Count}")]
41 public abstract class ConfigurationElementCollection : ConfigurationElement, ICollection, IEnumerable
43 ArrayList list = new ArrayList ();
49 int inheritedLimitIndex;
51 string addElementName = "add";
52 string clearElementName = "clear";
53 string removeElementName = "remove";
57 protected ConfigurationElementCollection ()
61 protected ConfigurationElementCollection (IComparer comparer)
63 this.comparer = comparer;
66 internal override void InitFromProperty (PropertyInformation propertyInfo)
68 ConfigurationCollectionAttribute colat = propertyInfo.Property.CollectionAttribute;
70 colat = ElementMap.GetMap (GetType ()).CollectionAttribute;
72 addElementName = colat.AddItemName;
73 clearElementName = colat.ClearItemsName;
74 removeElementName = colat.RemoveItemName;
76 base.InitFromProperty (propertyInfo);
79 #endregion // Constructors
83 public virtual ConfigurationElementCollectionType CollectionType {
84 get { return ConfigurationElementCollectionType.AddRemoveClearMap; }
89 return CollectionType == ConfigurationElementCollectionType.BasicMap ||
90 CollectionType == ConfigurationElementCollectionType.BasicMapAlternate;
96 return CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate ||
97 CollectionType == ConfigurationElementCollectionType.BasicMapAlternate;
102 get { return list.Count; }
105 protected virtual string ElementName {
106 get { return string.Empty; }
109 public bool EmitClear {
110 get { return emitClear; }
111 set { emitClear = value; }
114 public bool IsSynchronized {
115 get { return false; }
118 public object SyncRoot {
122 protected virtual bool ThrowOnDuplicate {
126 protected internal string AddElementName {
127 get { return addElementName; }
128 set { addElementName = value; }
131 protected internal string ClearElementName {
132 get { return clearElementName; }
133 set { clearElementName = value; }
136 protected internal string RemoveElementName {
137 get { return removeElementName; }
138 set { removeElementName = value; }
141 #endregion // Properties
145 protected virtual void BaseAdd (ConfigurationElement element)
147 BaseAdd (element, ThrowOnDuplicate);
150 protected void BaseAdd (ConfigurationElement element, bool throwIfExists)
152 if (throwIfExists && BaseIndexOf (element) != -1)
153 throw new ConfigurationException ("Duplicate element in collection");
155 throw new ConfigurationErrorsException ("Collection is read only.");
157 int old_index = IndexOfKey (GetElementKey (element));
159 list.Insert (inheritedLimitIndex, element);
160 inheritedLimitIndex++;
165 if (!IsAlternate && old_index != -1)
166 list.RemoveAt (old_index);
170 protected virtual void BaseAdd (int index, ConfigurationElement element)
172 if (ThrowOnDuplicate && BaseIndexOf (element) != -1)
173 throw new ConfigurationException ("Duplicate element in collection");
175 throw new ConfigurationErrorsException ("Collection is read only.");
177 if (IsAlternate && (index > inheritedLimitIndex))
178 throw new ConfigurationErrorsException ("Can't insert new elements below the inherited elements.");
179 if (!IsAlternate && (index <= inheritedLimitIndex))
180 throw new ConfigurationErrorsException ("Can't insert new elements above the inherited elements.");
182 list.Insert (index, element);
186 protected internal void BaseClear ()
189 throw new ConfigurationErrorsException ("Collection is read only.");
195 protected internal ConfigurationElement BaseGet (int index)
197 return (ConfigurationElement) list [index];
200 protected internal ConfigurationElement BaseGet (object key)
202 int index = IndexOfKey (key);
203 if (index != -1) return (ConfigurationElement) list [index];
207 protected internal object[] BaseGetAllKeys ()
209 object[] keys = new object [list.Count];
210 for (int n=0; n<list.Count; n++)
211 keys [n] = BaseGetKey (n);
215 protected internal object BaseGetKey (int index)
217 if (index < 0 || index >= list.Count)
218 throw new ConfigurationErrorsException (String.Format ("Index {0} is out of range", index));
220 return GetElementKey ((ConfigurationElement) list[index]).ToString ();
223 protected int BaseIndexOf (ConfigurationElement element)
225 return list.IndexOf (element);
228 int IndexOfKey (object key)
230 for (int n=0; n<list.Count; n++) {
231 if (CompareKeys (GetElementKey ((ConfigurationElement) list[n]), key))
237 protected internal bool BaseIsRemoved (object key)
241 foreach (ConfigurationElement elem in removed) {
242 if (CompareKeys (GetElementKey (elem), key))
248 protected internal void BaseRemove (object key)
251 throw new ConfigurationErrorsException ("Collection is read only.");
253 int index = IndexOfKey (key);
255 BaseRemoveAt (index);
260 protected internal void BaseRemoveAt (int index)
263 throw new ConfigurationErrorsException ("Collection is read only.");
265 ConfigurationElement elem = (ConfigurationElement) list [index];
266 if (!IsElementRemovable (elem))
267 throw new ConfigurationErrorsException ("Element can't be removed from element collection.");
269 if (inherited != null && inherited.Contains (elem))
270 throw new ConfigurationErrorsException ("Inherited items can't be removed.");
272 list.RemoveAt (index);
276 bool CompareKeys (object key1, object key2)
278 if (comparer != null)
279 return comparer.Compare (key1, key2) == 0;
281 return object.Equals (key1, key2);
284 public void CopyTo (ConfigurationElement[] array, int index)
286 list.CopyTo (array, index);
289 protected abstract ConfigurationElement CreateNewElement ();
291 protected virtual ConfigurationElement CreateNewElement (string elementName)
293 return CreateNewElement ();
296 ConfigurationElement CreateNewElementInternal (string elementName)
298 ConfigurationElement elem;
299 if (elementName == null)
300 elem = CreateNewElement ();
302 elem = CreateNewElement (elementName);
307 public override bool Equals (object compareTo)
309 ConfigurationElementCollection other = compareTo as ConfigurationElementCollection;
310 if (other == null) return false;
311 if (GetType() != other.GetType()) return false;
312 if (Count != other.Count) return false;
314 for (int n=0; n<Count; n++) {
315 if (!BaseGet (n).Equals (other.BaseGet (n)))
321 protected abstract object GetElementKey (ConfigurationElement element);
323 public override int GetHashCode ()
326 for (int n=0; n<Count; n++)
327 code += BaseGet (n).GetHashCode ();
331 void ICollection.CopyTo (Array arr, int index)
333 list.CopyTo (arr, index);
336 public IEnumerator GetEnumerator ()
338 return list.GetEnumerator ();
341 protected virtual bool IsElementName (string elementName)
346 protected virtual bool IsElementRemovable (ConfigurationElement element)
348 return !IsReadOnly ();
351 protected internal override bool IsModified ()
357 public override bool IsReadOnly ()
359 return base.IsReadOnly ();
362 internal override bool HasValues ()
364 return list.Count > 0;
367 protected internal override void Reset (ConfigurationElement parentElement)
369 bool basic = IsBasic;
371 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
372 for (int n=0; n<parent.Count; n++)
374 ConfigurationElement parentItem = parent.BaseGet (n);
375 ConfigurationElement item = CreateNewElementInternal (null);
376 item.Reset (parentItem);
380 if (inherited == null)
381 inherited = new ArrayList ();
382 inherited.Add (item);
386 inheritedLimitIndex = 0;
388 inheritedLimitIndex = Count - 1;
392 protected internal override void ResetModified ()
398 protected internal override void SetReadOnly ()
403 protected internal override bool SerializeElement (XmlWriter writer, bool serializeCollectionKey)
405 if (serializeCollectionKey) {
406 return base.SerializeElement (writer, serializeCollectionKey);
409 bool wroteData = false;
413 for (int n=0; n<list.Count; n++) {
414 ConfigurationElement elem = (ConfigurationElement) list [n];
415 if (ElementName != string.Empty)
416 wroteData = elem.SerializeToXmlElement (writer, ElementName) || wroteData;
418 wroteData = elem.SerializeElement (writer, false) || wroteData;
424 writer.WriteElementString (clearElementName, "");
428 if (removed != null) {
429 for (int n=0; n<removed.Count; n++) {
430 writer.WriteStartElement (removeElementName);
431 ((ConfigurationElement)removed[n]).SerializeElement (writer, true);
432 writer.WriteEndElement ();
434 wroteData = wroteData || removed.Count > 0;
437 for (int n=0; n<list.Count; n++) {
438 ConfigurationElement elem = (ConfigurationElement) list [n];
439 elem.SerializeToXmlElement (writer, addElementName);
442 wroteData = wroteData || list.Count > 0;
447 protected override bool OnDeserializeUnrecognizedElement (string elementName, XmlReader reader)
451 ConfigurationElement elem = null;
453 if (elementName == ElementName)
454 elem = CreateNewElementInternal (null);
455 if (IsElementName (elementName))
456 elem = CreateNewElementInternal (elementName);
459 elem.DeserializeElement (reader, false);
466 if (elementName == clearElementName) {
467 reader.MoveToContent ();
468 if (reader.MoveToNextAttribute ())
469 throw new ConfigurationErrorsException ("Unrecognized attribute '" + reader.LocalName + "'.");
470 reader.MoveToElement ();
477 else if (elementName == removeElementName) {
478 ConfigurationElement elem = CreateNewElementInternal (removeElementName);
479 elem.DeserializeElement (reader, true);
480 BaseRemove (GetElementKey (elem));
484 else if (elementName == addElementName) {
485 ConfigurationElement elem = CreateNewElementInternal (null);
486 elem.DeserializeElement (reader, false);
496 protected internal override void Unmerge (ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode updateMode)
498 ConfigurationElementCollection source = (ConfigurationElementCollection) sourceElement;
499 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
501 for (int n=0; n<source.Count; n++) {
502 ConfigurationElement sitem = source.BaseGet (n);
503 object key = source.GetElementKey (sitem);
504 ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
505 if (pitem != null && updateMode != ConfigurationSaveMode.Full) {
506 ConfigurationElement nitem = CreateNewElementInternal (null);
507 nitem.Unmerge (sitem, pitem, ConfigurationSaveMode.Minimal);
508 if (nitem.HasValues ())
512 ConfigurationElement nitem = CreateNewElementInternal (null);
513 nitem.Unmerge (sitem, null, ConfigurationSaveMode.Full);
518 if (updateMode == ConfigurationSaveMode.Full)
520 else if (parent != null) {
521 for (int n=0; n<parent.Count; n++) {
522 ConfigurationElement pitem = parent.BaseGet (n);
523 object key = parent.GetElementKey (pitem);
524 if (source.IndexOfKey (key) == -1) {
525 if (removed == null) removed = new ArrayList ();
532 #endregion // Methods