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;
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)
153 throw new ConfigurationErrorsException ("Collection is read only.");
155 int old_index = IndexOfKey (GetElementKey (element));
156 if (old_index >= 0) {
157 if (element.Equals (list [old_index]))
160 throw new ConfigurationException ("Duplicate element in collection");
163 list.Insert (inheritedLimitIndex, element);
164 inheritedLimitIndex++;
169 if (!IsAlternate && old_index != -1)
170 list.RemoveAt (old_index);
174 protected virtual void BaseAdd (int index, ConfigurationElement element)
176 if (ThrowOnDuplicate && BaseIndexOf (element) != -1)
177 throw new ConfigurationException ("Duplicate element in collection");
179 throw new ConfigurationErrorsException ("Collection is read only.");
181 if (IsAlternate && (index > inheritedLimitIndex))
182 throw new ConfigurationErrorsException ("Can't insert new elements below the inherited elements.");
183 if (!IsAlternate && (index <= inheritedLimitIndex))
184 throw new ConfigurationErrorsException ("Can't insert new elements above the inherited elements.");
186 list.Insert (index, element);
190 protected internal void BaseClear ()
193 throw new ConfigurationErrorsException ("Collection is read only.");
199 protected internal ConfigurationElement BaseGet (int index)
201 return (ConfigurationElement) list [index];
204 protected internal ConfigurationElement BaseGet (object key)
206 int index = IndexOfKey (key);
207 if (index != -1) return (ConfigurationElement) list [index];
211 protected internal object[] BaseGetAllKeys ()
213 object[] keys = new object [list.Count];
214 for (int n=0; n<list.Count; n++)
215 keys [n] = BaseGetKey (n);
219 protected internal object BaseGetKey (int index)
221 if (index < 0 || index >= list.Count)
222 throw new ConfigurationErrorsException (String.Format ("Index {0} is out of range", index));
224 return GetElementKey ((ConfigurationElement) list[index]).ToString ();
227 protected int BaseIndexOf (ConfigurationElement element)
229 return list.IndexOf (element);
232 int IndexOfKey (object key)
234 for (int n=0; n<list.Count; n++) {
235 if (CompareKeys (GetElementKey ((ConfigurationElement) list[n]), key))
241 protected internal bool BaseIsRemoved (object key)
245 foreach (ConfigurationElement elem in removed) {
246 if (CompareKeys (GetElementKey (elem), key))
252 protected internal void BaseRemove (object key)
255 throw new ConfigurationErrorsException ("Collection is read only.");
257 int index = IndexOfKey (key);
259 BaseRemoveAt (index);
264 protected internal void BaseRemoveAt (int index)
267 throw new ConfigurationErrorsException ("Collection is read only.");
269 ConfigurationElement elem = (ConfigurationElement) list [index];
270 if (!IsElementRemovable (elem))
271 throw new ConfigurationErrorsException ("Element can't be removed from element collection.");
273 if (inherited != null && inherited.Contains (elem))
274 throw new ConfigurationErrorsException ("Inherited items can't be removed.");
276 list.RemoveAt (index);
280 bool CompareKeys (object key1, object key2)
282 if (comparer != null)
283 return comparer.Compare (key1, key2) == 0;
285 return object.Equals (key1, key2);
288 public void CopyTo (ConfigurationElement[] array, int index)
290 list.CopyTo (array, index);
293 protected abstract ConfigurationElement CreateNewElement ();
295 protected virtual ConfigurationElement CreateNewElement (string elementName)
297 return CreateNewElement ();
300 ConfigurationElement CreateNewElementInternal (string elementName)
302 ConfigurationElement elem;
303 if (elementName == null)
304 elem = CreateNewElement ();
306 elem = CreateNewElement (elementName);
311 public override bool Equals (object compareTo)
313 ConfigurationElementCollection other = compareTo as ConfigurationElementCollection;
314 if (other == null) return false;
315 if (GetType() != other.GetType()) return false;
316 if (Count != other.Count) return false;
318 for (int n=0; n<Count; n++) {
319 if (!BaseGet (n).Equals (other.BaseGet (n)))
325 protected abstract object GetElementKey (ConfigurationElement element);
327 public override int GetHashCode ()
330 for (int n=0; n<Count; n++)
331 code += BaseGet (n).GetHashCode ();
335 void ICollection.CopyTo (Array arr, int index)
337 list.CopyTo (arr, index);
340 public IEnumerator GetEnumerator ()
342 return list.GetEnumerator ();
345 protected virtual bool IsElementName (string elementName)
350 protected virtual bool IsElementRemovable (ConfigurationElement element)
352 return !IsReadOnly ();
355 protected internal override bool IsModified ()
361 public override bool IsReadOnly ()
363 return base.IsReadOnly ();
366 internal override bool HasValues ()
368 return list.Count > 0;
371 protected internal override void Reset (ConfigurationElement parentElement)
373 bool basic = IsBasic;
375 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
376 for (int n=0; n<parent.Count; n++)
378 ConfigurationElement parentItem = parent.BaseGet (n);
379 ConfigurationElement item = CreateNewElementInternal (null);
380 item.Reset (parentItem);
384 if (inherited == null)
385 inherited = new ArrayList ();
386 inherited.Add (item);
390 inheritedLimitIndex = 0;
392 inheritedLimitIndex = Count - 1;
396 protected internal override void ResetModified ()
402 protected internal override void SetReadOnly ()
407 protected internal override bool SerializeElement (XmlWriter writer, bool serializeCollectionKey)
409 if (serializeCollectionKey) {
410 return base.SerializeElement (writer, serializeCollectionKey);
413 bool wroteData = false;
417 for (int n=0; n<list.Count; n++) {
418 ConfigurationElement elem = (ConfigurationElement) list [n];
419 if (ElementName != string.Empty)
420 wroteData = elem.SerializeToXmlElement (writer, ElementName) || wroteData;
422 wroteData = elem.SerializeElement (writer, false) || wroteData;
428 writer.WriteElementString (clearElementName, "");
432 if (removed != null) {
433 for (int n=0; n<removed.Count; n++) {
434 writer.WriteStartElement (removeElementName);
435 ((ConfigurationElement)removed[n]).SerializeElement (writer, true);
436 writer.WriteEndElement ();
438 wroteData = wroteData || removed.Count > 0;
441 for (int n=0; n<list.Count; n++) {
442 ConfigurationElement elem = (ConfigurationElement) list [n];
443 elem.SerializeToXmlElement (writer, addElementName);
446 wroteData = wroteData || list.Count > 0;
451 protected override bool OnDeserializeUnrecognizedElement (string elementName, XmlReader reader)
455 ConfigurationElement elem = null;
457 if (elementName == ElementName)
458 elem = CreateNewElementInternal (null);
459 if (IsElementName (elementName))
460 elem = CreateNewElementInternal (elementName);
463 elem.DeserializeElement (reader, false);
470 if (elementName == clearElementName) {
471 reader.MoveToContent ();
472 if (reader.MoveToNextAttribute ())
473 throw new ConfigurationErrorsException ("Unrecognized attribute '" + reader.LocalName + "'.");
474 reader.MoveToElement ();
481 else if (elementName == removeElementName) {
482 ConfigurationElement elem = CreateNewElementInternal (null);
483 ConfigurationRemoveElement removeElem = new ConfigurationRemoveElement (elem, this);
484 removeElem.DeserializeElement (reader, true);
485 BaseRemove (removeElem.KeyValue);
489 else if (elementName == addElementName) {
490 ConfigurationElement elem = CreateNewElementInternal (null);
491 elem.DeserializeElement (reader, false);
501 protected internal override void Unmerge (ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode updateMode)
503 ConfigurationElementCollection source = (ConfigurationElementCollection) sourceElement;
504 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
506 for (int n=0; n<source.Count; n++) {
507 ConfigurationElement sitem = source.BaseGet (n);
508 object key = source.GetElementKey (sitem);
509 ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
510 if (pitem != null && updateMode != ConfigurationSaveMode.Full) {
511 ConfigurationElement nitem = CreateNewElementInternal (null);
512 nitem.Unmerge (sitem, pitem, ConfigurationSaveMode.Minimal);
513 if (nitem.HasValues ())
517 ConfigurationElement nitem = CreateNewElementInternal (null);
518 nitem.Unmerge (sitem, null, ConfigurationSaveMode.Full);
523 if (updateMode == ConfigurationSaveMode.Full)
525 else if (parent != null) {
526 for (int n=0; n<parent.Count; n++) {
527 ConfigurationElement pitem = parent.BaseGet (n);
528 object key = parent.GetElementKey (pitem);
529 if (source.IndexOfKey (key) == -1) {
530 if (removed == null) removed = new ArrayList ();
537 #endregion // Methods