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 protected 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;
101 public virtual int Count {
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 virtual 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.");
158 list.Insert (inheritedLimitIndex, element);
159 inheritedLimitIndex++;
166 protected virtual void BaseAdd (int index, ConfigurationElement element)
168 // if (ThrowOnDuplicate && BaseIndexOf (element) != -1)
169 // throw new ConfigurationException ("Duplicate element in collection");
171 throw new ConfigurationErrorsException ("Collection is read only.");
173 if (IsAlternate && (index > inheritedLimitIndex))
174 throw new ConfigurationErrorsException ("Can't insert new elements below the inherited elements.");
175 if (!IsAlternate && (index <= inheritedLimitIndex))
176 throw new ConfigurationErrorsException ("Can't insert new elements above the inherited elements.");
178 list.Insert (index, element);
182 protected internal void BaseClear ()
185 throw new ConfigurationErrorsException ("Collection is read only.");
191 protected internal ConfigurationElement BaseGet (int index)
193 return (ConfigurationElement) list [index];
196 protected internal ConfigurationElement BaseGet (object key)
198 int index = IndexOfKey (key);
199 if (index != -1) return (ConfigurationElement) list [index];
203 protected internal object[] BaseGetAllKeys ()
205 object[] keys = new object [list.Count];
206 for (int n=0; n<list.Count; n++)
207 keys [n] = BaseGetKey (n);
211 protected internal object BaseGetKey (int index)
213 return GetElementKey ((ConfigurationElement) list[index]).ToString ();
216 protected int BaseIndexOf (ConfigurationElement element)
218 return list.IndexOf (element);
221 int IndexOfKey (object key)
223 for (int n=0; n<list.Count; n++) {
224 if (CompareKeys (GetElementKey ((ConfigurationElement) list[n]), key))
230 protected internal bool BaseIsRemoved (object key)
234 foreach (ConfigurationElement elem in removed) {
235 if (CompareKeys (GetElementKey (elem), key))
241 protected internal void BaseRemove (object key)
244 throw new ConfigurationErrorsException ("Collection is read only.");
246 int index = IndexOfKey (key);
248 BaseRemoveAt (index);
253 protected internal void BaseRemoveAt (int index)
256 throw new ConfigurationErrorsException ("Collection is read only.");
258 ConfigurationElement elem = (ConfigurationElement) list [index];
259 if (!IsElementRemovable (elem))
260 throw new ConfigurationErrorsException ("Element can't be removed from element collection.");
262 if (inherited != null && inherited.Contains (elem))
263 throw new ConfigurationErrorsException ("Inherited items can't be removed.");
265 list.RemoveAt (index);
269 bool CompareKeys (object key1, object key2)
271 if (comparer != null)
272 return comparer.Compare (key1, key2) == 0;
274 return object.Equals (key1, key2);
277 public void CopyTo (ConfigurationElement[] array, int index)
279 list.CopyTo (array, index);
282 protected abstract ConfigurationElement CreateNewElement ();
284 protected virtual ConfigurationElement CreateNewElement (string elementName)
286 return CreateNewElement ();
289 ConfigurationElement CreateNewElementInternal (string elementName)
291 ConfigurationElement elem;
292 if (elementName == null)
293 elem = CreateNewElement ();
295 elem = CreateNewElement (elementName);
300 public override bool Equals (object compareTo)
302 ConfigurationElementCollection other = compareTo as ConfigurationElementCollection;
303 if (other == null) return false;
304 if (GetType() != other.GetType()) return false;
305 if (Count != other.Count) return false;
307 for (int n=0; n<Count; n++) {
308 if (!BaseGet (n).Equals (other.BaseGet (n)))
314 protected abstract object GetElementKey (ConfigurationElement element);
316 public override int GetHashCode ()
319 for (int n=0; n<Count; n++)
320 code += BaseGet (n).GetHashCode ();
324 void ICollection.CopyTo (Array arr, int index)
326 list.CopyTo (arr, index);
329 public IEnumerator GetEnumerator ()
331 return list.GetEnumerator ();
334 protected virtual bool IsElementName (string elementName)
339 protected virtual bool IsElementRemovable (ConfigurationElement element)
341 return !IsReadOnly ();
344 protected internal override bool IsModified ()
349 internal override bool HasValues ()
351 return list.Count > 0;
354 protected internal override void Reset (ConfigurationElement parentElement)
356 bool basic = IsBasic;
358 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
359 for (int n=0; n<parent.Count; n++)
361 ConfigurationElement parentItem = parent.BaseGet (n);
362 ConfigurationElement item = CreateNewElementInternal (parentItem.GetType().FullName);
363 item.Reset (parentItem);
367 if (inherited == null)
368 inherited = new ArrayList ();
369 inherited.Add (item);
373 inheritedLimitIndex = 0;
375 inheritedLimitIndex = Count - 1;
379 protected internal override void ResetModified ()
384 protected internal override bool SerializeElement (XmlWriter writer, bool serializeCollectionKey)
386 if (serializeCollectionKey) {
387 return base.SerializeElement (writer, serializeCollectionKey);
390 bool wroteData = false;
394 for (int n=0; n<list.Count; n++) {
395 ConfigurationElement elem = (ConfigurationElement) list [n];
396 if (ElementName != string.Empty)
397 wroteData = elem.SerializeToXmlElement (writer, ElementName) || wroteData;
399 wroteData = elem.SerializeElement (writer, false) || wroteData;
405 writer.WriteElementString (clearElementName, "");
409 if (removed != null) {
410 for (int n=0; n<removed.Count; n++) {
411 writer.WriteStartElement (removeElementName);
412 ((ConfigurationElement)removed[n]).SerializeElement (writer, true);
413 writer.WriteEndElement ();
415 wroteData = wroteData || removed.Count > 0;
418 for (int n=0; n<list.Count; n++) {
419 ConfigurationElement elem = (ConfigurationElement) list [n];
420 elem.SerializeToXmlElement (writer, addElementName);
423 wroteData = wroteData || list.Count > 0;
428 protected override bool OnDeserializeUnrecognizedElement (string elementName, XmlReader reader)
432 ConfigurationElement elem = null;
434 if (elementName == ElementName)
435 elem = CreateNewElementInternal (null);
436 if (IsElementName (elementName))
437 elem = CreateNewElementInternal (elementName);
440 elem.DeserializeElement (reader, false);
447 if (elementName == clearElementName) {
448 ConfigurationElement elem = CreateNewElementInternal (null);
449 elem.DeserializeElement (reader, true);
455 else if (elementName == removeElementName) {
456 ConfigurationElement elem = CreateNewElementInternal (null);
457 elem.DeserializeElement (reader, true);
458 BaseRemove (GetElementKey (elem));
462 else if (elementName == addElementName) {
463 ConfigurationElement elem = CreateNewElementInternal (null);
464 elem.DeserializeElement (reader, false);
474 protected internal override void Unmerge (ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode updateMode)
476 ConfigurationElementCollection source = (ConfigurationElementCollection) sourceElement;
477 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
479 for (int n=0; n<source.Count; n++) {
480 ConfigurationElement sitem = source.BaseGet (n);
481 object key = source.GetElementKey (sitem);
482 ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
483 if (pitem != null && updateMode != ConfigurationSaveMode.Full) {
484 ConfigurationElement nitem = CreateNewElementInternal (pitem.GetType().FullName);
485 nitem.Unmerge (sitem, pitem, ConfigurationSaveMode.Minimal);
486 if (nitem.HasValues ())
490 ConfigurationElement nitem = CreateNewElementInternal (sitem.GetType().FullName);
491 nitem.Unmerge (sitem, null, ConfigurationSaveMode.Full);
496 if (updateMode == ConfigurationSaveMode.Full)
498 else if (parent != null) {
499 for (int n=0; n<parent.Count; n++) {
500 ConfigurationElement pitem = parent.BaseGet (n);
501 object key = parent.GetElementKey (pitem);
502 if (source.IndexOfKey (key) == -1) {
503 if (removed == null) removed = new ArrayList ();
510 #endregion // Methods