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 partial 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;
71 colat = Attribute.GetCustomAttribute (propertyInfo.Type, typeof (ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;
74 addElementName = colat.AddItemName;
75 clearElementName = colat.ClearItemsName;
76 removeElementName = colat.RemoveItemName;
78 base.InitFromProperty (propertyInfo);
81 #endregion // Constructors
85 public virtual ConfigurationElementCollectionType CollectionType {
86 get { return ConfigurationElementCollectionType.AddRemoveClearMap; }
91 return CollectionType == ConfigurationElementCollectionType.BasicMap ||
92 CollectionType == ConfigurationElementCollectionType.BasicMapAlternate;
98 return CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate ||
99 CollectionType == ConfigurationElementCollectionType.BasicMapAlternate;
104 get { return list.Count; }
107 protected virtual string ElementName {
108 get { return string.Empty; }
111 public bool EmitClear {
112 get { return emitClear; }
113 set { emitClear = value; }
116 public bool IsSynchronized {
117 get { return false; }
120 public object SyncRoot {
124 protected virtual bool ThrowOnDuplicate {
126 if (CollectionType != ConfigurationElementCollectionType.AddRemoveClearMap &&
127 CollectionType != ConfigurationElementCollectionType.AddRemoveClearMapAlternate)
134 protected internal string AddElementName {
135 get { return addElementName; }
136 set { addElementName = value; }
139 protected internal string ClearElementName {
140 get { return clearElementName; }
141 set { clearElementName = value; }
144 protected internal string RemoveElementName {
145 get { return removeElementName; }
146 set { removeElementName = value; }
149 #endregion // Properties
153 protected virtual void BaseAdd (ConfigurationElement element)
155 BaseAdd (element, ThrowOnDuplicate);
158 protected void BaseAdd (ConfigurationElement element, bool throwIfExists)
161 throw new ConfigurationErrorsException ("Collection is read only.");
164 list.Insert (inheritedLimitIndex, element);
165 inheritedLimitIndex++;
168 int old_index = IndexOfKey (GetElementKey (element));
169 if (old_index >= 0) {
170 if (element.Equals (list [old_index]))
173 throw new ConfigurationException ("Duplicate element in collection");
174 list.RemoveAt (old_index);
182 protected virtual void BaseAdd (int index, ConfigurationElement element)
184 if (ThrowOnDuplicate && BaseIndexOf (element) != -1)
185 throw new ConfigurationException ("Duplicate element in collection");
187 throw new ConfigurationErrorsException ("Collection is read only.");
189 if (IsAlternate && (index > inheritedLimitIndex))
190 throw new ConfigurationErrorsException ("Can't insert new elements below the inherited elements.");
191 if (!IsAlternate && (index <= inheritedLimitIndex))
192 throw new ConfigurationErrorsException ("Can't insert new elements above the inherited elements.");
194 list.Insert (index, element);
198 protected internal void BaseClear ()
201 throw new ConfigurationErrorsException ("Collection is read only.");
207 protected internal ConfigurationElement BaseGet (int index)
209 return (ConfigurationElement) list [index];
212 protected internal ConfigurationElement BaseGet (object key)
214 int index = IndexOfKey (key);
215 if (index != -1) return (ConfigurationElement) list [index];
219 protected internal object[] BaseGetAllKeys ()
221 object[] keys = new object [list.Count];
222 for (int n=0; n<list.Count; n++)
223 keys [n] = BaseGetKey (n);
227 protected internal object BaseGetKey (int index)
229 if (index < 0 || index >= list.Count)
230 throw new ConfigurationErrorsException (String.Format ("Index {0} is out of range", index));
232 return GetElementKey ((ConfigurationElement) list[index]).ToString ();
235 protected int BaseIndexOf (ConfigurationElement element)
237 return list.IndexOf (element);
240 int IndexOfKey (object key)
242 for (int n=0; n<list.Count; n++) {
243 if (CompareKeys (GetElementKey ((ConfigurationElement) list[n]), key))
249 protected internal bool BaseIsRemoved (object key)
253 foreach (ConfigurationElement elem in removed) {
254 if (CompareKeys (GetElementKey (elem), key))
260 protected internal void BaseRemove (object key)
263 throw new ConfigurationErrorsException ("Collection is read only.");
265 int index = IndexOfKey (key);
267 BaseRemoveAt (index);
272 protected internal void BaseRemoveAt (int index)
275 throw new ConfigurationErrorsException ("Collection is read only.");
277 ConfigurationElement elem = (ConfigurationElement) list [index];
278 if (!IsElementRemovable (elem))
279 throw new ConfigurationErrorsException ("Element can't be removed from element collection.");
281 if (inherited != null && inherited.Contains (elem))
282 throw new ConfigurationErrorsException ("Inherited items can't be removed.");
284 list.RemoveAt (index);
287 if (inheritedLimitIndex > 0)
288 inheritedLimitIndex--;
293 bool CompareKeys (object key1, object key2)
295 if (comparer != null)
296 return comparer.Compare (key1, key2) == 0;
298 return object.Equals (key1, key2);
301 public void CopyTo (ConfigurationElement[] array, int index)
303 list.CopyTo (array, index);
306 protected abstract ConfigurationElement CreateNewElement ();
308 protected virtual ConfigurationElement CreateNewElement (string elementName)
310 return CreateNewElement ();
313 ConfigurationElement CreateNewElementInternal (string elementName)
315 ConfigurationElement elem;
316 if (elementName == null)
317 elem = CreateNewElement ();
319 elem = CreateNewElement (elementName);
324 public override bool Equals (object compareTo)
326 ConfigurationElementCollection other = compareTo as ConfigurationElementCollection;
327 if (other == null) return false;
328 if (GetType() != other.GetType()) return false;
329 if (Count != other.Count) return false;
331 for (int n=0; n<Count; n++) {
332 if (!BaseGet (n).Equals (other.BaseGet (n)))
338 protected abstract object GetElementKey (ConfigurationElement element);
340 public override int GetHashCode ()
343 for (int n=0; n<Count; n++)
344 code += BaseGet (n).GetHashCode ();
348 void ICollection.CopyTo (Array arr, int index)
350 list.CopyTo (arr, index);
353 public IEnumerator GetEnumerator ()
355 return list.GetEnumerator ();
358 protected virtual bool IsElementName (string elementName)
363 protected virtual bool IsElementRemovable (ConfigurationElement element)
365 return !IsReadOnly ();
368 protected internal override bool IsModified ()
374 public override bool IsReadOnly ()
376 return base.IsReadOnly ();
379 internal override bool HasValues ()
381 return list.Count > 0;
384 protected internal override void Reset (ConfigurationElement parentElement)
386 bool basic = IsBasic;
388 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
389 for (int n=0; n<parent.Count; n++)
391 ConfigurationElement parentItem = parent.BaseGet (n);
392 ConfigurationElement item = CreateNewElementInternal (null);
393 item.Reset (parentItem);
397 if (inherited == null)
398 inherited = new ArrayList ();
399 inherited.Add (item);
403 inheritedLimitIndex = 0;
405 inheritedLimitIndex = Count - 1;
409 protected internal override void ResetModified ()
415 protected internal override void SetReadOnly ()
420 protected internal override bool SerializeElement (XmlWriter writer, bool serializeCollectionKey)
422 if (serializeCollectionKey) {
423 return base.SerializeElement (writer, serializeCollectionKey);
426 bool wroteData = false;
430 for (int n=0; n<list.Count; n++) {
431 ConfigurationElement elem = (ConfigurationElement) list [n];
432 if (ElementName != string.Empty)
433 wroteData = elem.SerializeToXmlElement (writer, ElementName) || wroteData;
435 wroteData = elem.SerializeElement (writer, false) || wroteData;
441 writer.WriteElementString (clearElementName, "");
445 if (removed != null) {
446 for (int n=0; n<removed.Count; n++) {
447 writer.WriteStartElement (removeElementName);
448 ((ConfigurationElement)removed[n]).SerializeElement (writer, true);
449 writer.WriteEndElement ();
451 wroteData = wroteData || removed.Count > 0;
454 for (int n=0; n<list.Count; n++) {
455 ConfigurationElement elem = (ConfigurationElement) list [n];
456 elem.SerializeToXmlElement (writer, addElementName);
459 wroteData = wroteData || list.Count > 0;
464 protected override bool OnDeserializeUnrecognizedElement (string elementName, XmlReader reader)
468 ConfigurationElement elem = null;
470 if (elementName == ElementName)
471 elem = CreateNewElementInternal (null);
472 if (IsElementName (elementName))
473 elem = CreateNewElementInternal (elementName);
476 elem.DeserializeElement (reader, false);
483 if (elementName == clearElementName) {
484 reader.MoveToContent ();
485 if (reader.MoveToNextAttribute ())
486 throw new ConfigurationErrorsException ("Unrecognized attribute '" + reader.LocalName + "'.");
487 reader.MoveToElement ();
494 else if (elementName == removeElementName) {
495 ConfigurationElement elem = CreateNewElementInternal (null);
496 ConfigurationRemoveElement removeElem = new ConfigurationRemoveElement (elem, this);
497 removeElem.DeserializeElement (reader, true);
498 BaseRemove (removeElem.KeyValue);
502 else if (elementName == addElementName) {
503 ConfigurationElement elem = CreateNewElementInternal (null);
504 elem.DeserializeElement (reader, false);
514 protected internal override void Unmerge (ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode updateMode)
516 ConfigurationElementCollection source = (ConfigurationElementCollection) sourceElement;
517 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
519 for (int n=0; n<source.Count; n++) {
520 ConfigurationElement sitem = source.BaseGet (n);
521 object key = source.GetElementKey (sitem);
522 ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
523 if (pitem != null && updateMode != ConfigurationSaveMode.Full) {
524 ConfigurationElement nitem = CreateNewElementInternal (null);
525 nitem.Unmerge (sitem, pitem, ConfigurationSaveMode.Minimal);
526 if (nitem.HasValues ())
530 ConfigurationElement nitem = CreateNewElementInternal (null);
531 nitem.Unmerge (sitem, null, ConfigurationSaveMode.Full);
536 if (updateMode == ConfigurationSaveMode.Full)
538 else if (parent != null) {
539 for (int n=0; n<parent.Count; n++) {
540 ConfigurationElement pitem = parent.BaseGet (n);
541 object key = parent.GetElementKey (pitem);
542 if (source.IndexOfKey (key) == -1) {
543 if (removed == null) removed = new ArrayList ();
550 #endregion // Methods