2 // System.Configuration.ConfigurationElementCollection.cs
5 // Tim Coleman (tim@timcoleman.com)
6 // Martin Baulig <martin.baulig@xamarin.com>
8 // Copyright (C) Tim Coleman, 2004
9 // Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
36 using System.Collections;
37 using System.Diagnostics;
40 namespace System.Configuration
42 [DebuggerDisplayAttribute ("Count = {Count}")]
43 public abstract partial class ConfigurationElementCollection : ConfigurationElement, ICollection, IEnumerable
45 ArrayList list = new ArrayList ();
51 int inheritedLimitIndex;
53 string addElementName = "add";
54 string clearElementName = "clear";
55 string removeElementName = "remove";
59 protected ConfigurationElementCollection ()
63 protected ConfigurationElementCollection (IComparer comparer)
65 this.comparer = comparer;
68 internal override void InitFromProperty (PropertyInformation propertyInfo)
70 ConfigurationCollectionAttribute colat = propertyInfo.Property.CollectionAttribute;
73 colat = Attribute.GetCustomAttribute (propertyInfo.Type, typeof (ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;
76 addElementName = colat.AddItemName;
77 clearElementName = colat.ClearItemsName;
78 removeElementName = colat.RemoveItemName;
80 base.InitFromProperty (propertyInfo);
83 #endregion // Constructors
87 public virtual ConfigurationElementCollectionType CollectionType {
88 get { return ConfigurationElementCollectionType.AddRemoveClearMap; }
93 return CollectionType == ConfigurationElementCollectionType.BasicMap ||
94 CollectionType == ConfigurationElementCollectionType.BasicMapAlternate;
100 return CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate ||
101 CollectionType == ConfigurationElementCollectionType.BasicMapAlternate;
106 get { return list.Count; }
109 protected virtual string ElementName {
110 get { return string.Empty; }
113 public bool EmitClear {
114 get { return emitClear; }
115 set { emitClear = value; }
118 public bool IsSynchronized {
119 get { return false; }
122 public object SyncRoot {
126 protected virtual bool ThrowOnDuplicate {
128 if (CollectionType != ConfigurationElementCollectionType.AddRemoveClearMap &&
129 CollectionType != ConfigurationElementCollectionType.AddRemoveClearMapAlternate)
136 protected internal string AddElementName {
137 get { return addElementName; }
138 set { addElementName = value; }
141 protected internal string ClearElementName {
142 get { return clearElementName; }
143 set { clearElementName = value; }
146 protected internal string RemoveElementName {
147 get { return removeElementName; }
148 set { removeElementName = value; }
151 #endregion // Properties
155 protected virtual void BaseAdd (ConfigurationElement element)
157 BaseAdd (element, ThrowOnDuplicate);
160 protected void BaseAdd (ConfigurationElement element, bool throwIfExists)
163 throw new ConfigurationErrorsException ("Collection is read only.");
166 list.Insert (inheritedLimitIndex, element);
167 inheritedLimitIndex++;
170 int old_index = IndexOfKey (GetElementKey (element));
171 if (old_index >= 0) {
172 if (element.Equals (list [old_index]))
175 throw new ConfigurationErrorsException ("Duplicate element in collection");
176 list.RemoveAt (old_index);
184 protected virtual void BaseAdd (int index, ConfigurationElement element)
186 if (ThrowOnDuplicate && BaseIndexOf (element) != -1)
187 throw new ConfigurationErrorsException ("Duplicate element in collection");
189 throw new ConfigurationErrorsException ("Collection is read only.");
191 if (IsAlternate && (index > inheritedLimitIndex))
192 throw new ConfigurationErrorsException ("Can't insert new elements below the inherited elements.");
193 if (!IsAlternate && (index <= inheritedLimitIndex))
194 throw new ConfigurationErrorsException ("Can't insert new elements above the inherited elements.");
196 list.Insert (index, element);
200 protected internal void BaseClear ()
203 throw new ConfigurationErrorsException ("Collection is read only.");
209 protected internal ConfigurationElement BaseGet (int index)
211 return (ConfigurationElement) list [index];
214 protected internal ConfigurationElement BaseGet (object key)
216 int index = IndexOfKey (key);
217 if (index != -1) return (ConfigurationElement) list [index];
221 protected internal object[] BaseGetAllKeys ()
223 object[] keys = new object [list.Count];
224 for (int n=0; n<list.Count; n++)
225 keys [n] = BaseGetKey (n);
229 protected internal object BaseGetKey (int index)
231 if (index < 0 || index >= list.Count)
232 throw new ConfigurationErrorsException (String.Format ("Index {0} is out of range", index));
234 return GetElementKey ((ConfigurationElement) list[index]).ToString ();
237 protected int BaseIndexOf (ConfigurationElement element)
239 return list.IndexOf (element);
242 int IndexOfKey (object key)
244 for (int n=0; n<list.Count; n++) {
245 if (CompareKeys (GetElementKey ((ConfigurationElement) list[n]), key))
251 protected internal bool BaseIsRemoved (object key)
255 foreach (ConfigurationElement elem in removed) {
256 if (CompareKeys (GetElementKey (elem), key))
262 protected internal void BaseRemove (object key)
265 throw new ConfigurationErrorsException ("Collection is read only.");
267 int index = IndexOfKey (key);
269 BaseRemoveAt (index);
274 protected internal void BaseRemoveAt (int index)
277 throw new ConfigurationErrorsException ("Collection is read only.");
279 ConfigurationElement elem = (ConfigurationElement) list [index];
280 if (!IsElementRemovable (elem))
281 throw new ConfigurationErrorsException ("Element can't be removed from element collection.");
283 if (inherited != null && inherited.Contains (elem))
284 throw new ConfigurationErrorsException ("Inherited items can't be removed.");
286 list.RemoveAt (index);
289 if (inheritedLimitIndex > 0)
290 inheritedLimitIndex--;
296 bool CompareKeys (object key1, object key2)
298 if (comparer != null)
299 return comparer.Compare (key1, key2) == 0;
301 return object.Equals (key1, key2);
304 public void CopyTo (ConfigurationElement[] array, int index)
306 list.CopyTo (array, index);
309 protected abstract ConfigurationElement CreateNewElement ();
311 protected virtual ConfigurationElement CreateNewElement (string elementName)
313 return CreateNewElement ();
316 ConfigurationElement CreateNewElementInternal (string elementName)
318 ConfigurationElement elem;
319 if (elementName == null)
320 elem = CreateNewElement ();
322 elem = CreateNewElement (elementName);
327 public override bool Equals (object compareTo)
329 ConfigurationElementCollection other = compareTo as ConfigurationElementCollection;
330 if (other == null) return false;
331 if (GetType() != other.GetType()) return false;
332 if (Count != other.Count) return false;
334 for (int n=0; n<Count; n++) {
335 if (!BaseGet (n).Equals (other.BaseGet (n)))
341 protected abstract object GetElementKey (ConfigurationElement element);
343 public override int GetHashCode ()
346 for (int n=0; n<Count; n++)
347 code += BaseGet (n).GetHashCode ();
351 void ICollection.CopyTo (Array arr, int index)
353 list.CopyTo (arr, index);
356 public IEnumerator GetEnumerator ()
358 return list.GetEnumerator ();
361 protected virtual bool IsElementName (string elementName)
366 protected virtual bool IsElementRemovable (ConfigurationElement element)
368 return !IsReadOnly ();
371 protected internal override bool IsModified ()
376 for (int n=0; n<list.Count; n++) {
377 ConfigurationElement elem = (ConfigurationElement) list [n];
378 if (!elem.IsModified ())
388 public override bool IsReadOnly ()
390 return base.IsReadOnly ();
393 internal override void PrepareSave (ConfigurationElement parentElement, ConfigurationSaveMode mode)
395 var parent = (ConfigurationElementCollection)parentElement;
396 base.PrepareSave (parentElement, mode);
398 for (int n=0; n<list.Count; n++) {
399 ConfigurationElement elem = (ConfigurationElement) list [n];
400 object key = GetElementKey (elem);
401 ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
403 elem.PrepareSave (pitem, mode);
407 internal override bool HasValues (ConfigurationElement parentElement, ConfigurationSaveMode mode)
409 var parent = (ConfigurationElementCollection)parentElement;
411 if (mode == ConfigurationSaveMode.Full)
412 return list.Count > 0;
414 for (int n=0; n<list.Count; n++) {
415 ConfigurationElement elem = (ConfigurationElement) list [n];
416 object key = GetElementKey (elem);
417 ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
419 if (elem.HasValues (pitem, mode))
426 protected internal override void Reset (ConfigurationElement parentElement)
428 bool basic = IsBasic;
430 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
431 for (int n=0; n<parent.Count; n++)
433 ConfigurationElement parentItem = parent.BaseGet (n);
434 ConfigurationElement item = CreateNewElementInternal (null);
435 item.Reset (parentItem);
439 if (inherited == null)
440 inherited = new ArrayList ();
441 inherited.Add (item);
445 inheritedLimitIndex = 0;
447 inheritedLimitIndex = Count - 1;
451 protected internal override void ResetModified ()
454 for (int n=0; n<list.Count; n++) {
455 ConfigurationElement elem = (ConfigurationElement) list [n];
456 elem.ResetModified ();
461 protected internal override void SetReadOnly ()
466 protected internal override bool SerializeElement (XmlWriter writer, bool serializeCollectionKey)
468 if (serializeCollectionKey) {
469 return base.SerializeElement (writer, serializeCollectionKey);
472 bool wroteData = false;
476 for (int n=0; n<list.Count; n++) {
477 ConfigurationElement elem = (ConfigurationElement) list [n];
478 if (ElementName != string.Empty)
479 wroteData = elem.SerializeToXmlElement (writer, ElementName) || wroteData;
481 wroteData = elem.SerializeElement (writer, false) || wroteData;
487 writer.WriteElementString (clearElementName, "");
491 if (removed != null) {
492 for (int n=0; n<removed.Count; n++) {
493 writer.WriteStartElement (removeElementName);
494 ((ConfigurationElement)removed[n]).SerializeElement (writer, true);
495 writer.WriteEndElement ();
497 wroteData = wroteData || removed.Count > 0;
500 for (int n=0; n<list.Count; n++) {
501 ConfigurationElement elem = (ConfigurationElement) list [n];
502 elem.SerializeToXmlElement (writer, addElementName);
505 wroteData = wroteData || list.Count > 0;
510 protected override bool OnDeserializeUnrecognizedElement (string elementName, XmlReader reader)
514 ConfigurationElement elem = null;
516 if (elementName == ElementName)
517 elem = CreateNewElementInternal (null);
518 if (IsElementName (elementName))
519 elem = CreateNewElementInternal (elementName);
522 elem.DeserializeElement (reader, false);
529 if (elementName == clearElementName) {
530 reader.MoveToContent ();
531 if (reader.MoveToNextAttribute ())
532 throw new ConfigurationErrorsException ("Unrecognized attribute '" + reader.LocalName + "'.");
533 reader.MoveToElement ();
540 else if (elementName == removeElementName) {
541 ConfigurationElement elem = CreateNewElementInternal (null);
542 ConfigurationRemoveElement removeElem = new ConfigurationRemoveElement (elem, this);
543 removeElem.DeserializeElement (reader, true);
544 BaseRemove (removeElem.KeyValue);
548 else if (elementName == addElementName) {
549 ConfigurationElement elem = CreateNewElementInternal (null);
550 elem.DeserializeElement (reader, false);
560 protected internal override void Unmerge (ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode updateMode)
562 ConfigurationElementCollection source = (ConfigurationElementCollection) sourceElement;
563 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
565 for (int n=0; n<source.Count; n++) {
566 ConfigurationElement sitem = source.BaseGet (n);
567 object key = source.GetElementKey (sitem);
568 ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
569 ConfigurationElement nitem = CreateNewElementInternal (null);
570 if (pitem != null && updateMode != ConfigurationSaveMode.Full) {
571 nitem.Unmerge (sitem, pitem, updateMode);
572 if (nitem.HasValues (pitem, updateMode))
575 nitem.Unmerge (sitem, null, ConfigurationSaveMode.Full);
580 if (updateMode == ConfigurationSaveMode.Full)
582 else if (parent != null) {
583 for (int n=0; n<parent.Count; n++) {
584 ConfigurationElement pitem = parent.BaseGet (n);
585 object key = parent.GetElementKey (pitem);
586 if (source.IndexOfKey (key) == -1) {
587 if (removed == null) removed = new ArrayList ();
594 #endregion // Methods