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);
288 bool CompareKeys (object key1, object key2)
290 if (comparer != null)
291 return comparer.Compare (key1, key2) == 0;
293 return object.Equals (key1, key2);
296 public void CopyTo (ConfigurationElement[] array, int index)
298 list.CopyTo (array, index);
301 protected abstract ConfigurationElement CreateNewElement ();
303 protected virtual ConfigurationElement CreateNewElement (string elementName)
305 return CreateNewElement ();
308 ConfigurationElement CreateNewElementInternal (string elementName)
310 ConfigurationElement elem;
311 if (elementName == null)
312 elem = CreateNewElement ();
314 elem = CreateNewElement (elementName);
319 public override bool Equals (object compareTo)
321 ConfigurationElementCollection other = compareTo as ConfigurationElementCollection;
322 if (other == null) return false;
323 if (GetType() != other.GetType()) return false;
324 if (Count != other.Count) return false;
326 for (int n=0; n<Count; n++) {
327 if (!BaseGet (n).Equals (other.BaseGet (n)))
333 protected abstract object GetElementKey (ConfigurationElement element);
335 public override int GetHashCode ()
338 for (int n=0; n<Count; n++)
339 code += BaseGet (n).GetHashCode ();
343 void ICollection.CopyTo (Array arr, int index)
345 list.CopyTo (arr, index);
348 public IEnumerator GetEnumerator ()
350 return list.GetEnumerator ();
353 protected virtual bool IsElementName (string elementName)
358 protected virtual bool IsElementRemovable (ConfigurationElement element)
360 return !IsReadOnly ();
363 protected internal override bool IsModified ()
369 public override bool IsReadOnly ()
371 return base.IsReadOnly ();
374 internal override bool HasValues ()
376 return list.Count > 0;
379 protected internal override void Reset (ConfigurationElement parentElement)
381 bool basic = IsBasic;
383 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
384 for (int n=0; n<parent.Count; n++)
386 ConfigurationElement parentItem = parent.BaseGet (n);
387 ConfigurationElement item = CreateNewElementInternal (null);
388 item.Reset (parentItem);
392 if (inherited == null)
393 inherited = new ArrayList ();
394 inherited.Add (item);
398 inheritedLimitIndex = 0;
400 inheritedLimitIndex = Count - 1;
404 protected internal override void ResetModified ()
410 protected internal override void SetReadOnly ()
415 protected internal override bool SerializeElement (XmlWriter writer, bool serializeCollectionKey)
417 if (serializeCollectionKey) {
418 return base.SerializeElement (writer, serializeCollectionKey);
421 bool wroteData = false;
425 for (int n=0; n<list.Count; n++) {
426 ConfigurationElement elem = (ConfigurationElement) list [n];
427 if (ElementName != string.Empty)
428 wroteData = elem.SerializeToXmlElement (writer, ElementName) || wroteData;
430 wroteData = elem.SerializeElement (writer, false) || wroteData;
436 writer.WriteElementString (clearElementName, "");
440 if (removed != null) {
441 for (int n=0; n<removed.Count; n++) {
442 writer.WriteStartElement (removeElementName);
443 ((ConfigurationElement)removed[n]).SerializeElement (writer, true);
444 writer.WriteEndElement ();
446 wroteData = wroteData || removed.Count > 0;
449 for (int n=0; n<list.Count; n++) {
450 ConfigurationElement elem = (ConfigurationElement) list [n];
451 elem.SerializeToXmlElement (writer, addElementName);
454 wroteData = wroteData || list.Count > 0;
459 protected override bool OnDeserializeUnrecognizedElement (string elementName, XmlReader reader)
463 ConfigurationElement elem = null;
465 if (elementName == ElementName)
466 elem = CreateNewElementInternal (null);
467 if (IsElementName (elementName))
468 elem = CreateNewElementInternal (elementName);
471 elem.DeserializeElement (reader, false);
478 if (elementName == clearElementName) {
479 reader.MoveToContent ();
480 if (reader.MoveToNextAttribute ())
481 throw new ConfigurationErrorsException ("Unrecognized attribute '" + reader.LocalName + "'.");
482 reader.MoveToElement ();
489 else if (elementName == removeElementName) {
490 ConfigurationElement elem = CreateNewElementInternal (null);
491 ConfigurationRemoveElement removeElem = new ConfigurationRemoveElement (elem, this);
492 removeElem.DeserializeElement (reader, true);
493 BaseRemove (removeElem.KeyValue);
497 else if (elementName == addElementName) {
498 ConfigurationElement elem = CreateNewElementInternal (null);
499 elem.DeserializeElement (reader, false);
509 protected internal override void Unmerge (ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode updateMode)
511 ConfigurationElementCollection source = (ConfigurationElementCollection) sourceElement;
512 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
514 for (int n=0; n<source.Count; n++) {
515 ConfigurationElement sitem = source.BaseGet (n);
516 object key = source.GetElementKey (sitem);
517 ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
518 if (pitem != null && updateMode != ConfigurationSaveMode.Full) {
519 ConfigurationElement nitem = CreateNewElementInternal (null);
520 nitem.Unmerge (sitem, pitem, ConfigurationSaveMode.Minimal);
521 if (nitem.HasValues ())
525 ConfigurationElement nitem = CreateNewElementInternal (null);
526 nitem.Unmerge (sitem, null, ConfigurationSaveMode.Full);
531 if (updateMode == ConfigurationSaveMode.Full)
533 else if (parent != null) {
534 for (int n=0; n<parent.Count; n++) {
535 ConfigurationElement pitem = parent.BaseGet (n);
536 object key = parent.GetElementKey (pitem);
537 if (source.IndexOfKey (key) == -1) {
538 if (removed == null) removed = new ArrayList ();
545 #endregion // Methods