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)
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 ConfigurationErrorsException ("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 ConfigurationErrorsException ("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--;
294 bool CompareKeys (object key1, object key2)
296 if (comparer != null)
297 return comparer.Compare (key1, key2) == 0;
299 return object.Equals (key1, key2);
302 public void CopyTo (ConfigurationElement[] array, int index)
304 list.CopyTo (array, index);
307 protected abstract ConfigurationElement CreateNewElement ();
309 protected virtual ConfigurationElement CreateNewElement (string elementName)
311 return CreateNewElement ();
314 ConfigurationElement CreateNewElementInternal (string elementName)
316 ConfigurationElement elem;
317 if (elementName == null)
318 elem = CreateNewElement ();
320 elem = CreateNewElement (elementName);
325 public override bool Equals (object compareTo)
327 ConfigurationElementCollection other = compareTo as ConfigurationElementCollection;
328 if (other == null) return false;
329 if (GetType() != other.GetType()) return false;
330 if (Count != other.Count) return false;
332 for (int n=0; n<Count; n++) {
333 if (!BaseGet (n).Equals (other.BaseGet (n)))
339 protected abstract object GetElementKey (ConfigurationElement element);
341 public override int GetHashCode ()
344 for (int n=0; n<Count; n++)
345 code += BaseGet (n).GetHashCode ();
349 void ICollection.CopyTo (Array arr, int index)
351 list.CopyTo (arr, index);
354 public IEnumerator GetEnumerator ()
356 return list.GetEnumerator ();
359 protected virtual bool IsElementName (string elementName)
364 protected virtual bool IsElementRemovable (ConfigurationElement element)
366 return !IsReadOnly ();
369 protected internal override bool IsModified ()
374 for (int n=0; n<list.Count; n++) {
375 ConfigurationElement elem = (ConfigurationElement) list [n];
376 if (!elem.IsModified ())
386 public override bool IsReadOnly ()
388 return base.IsReadOnly ();
391 internal override void PrepareSave (ConfigurationElement parentElement, ConfigurationSaveMode mode)
393 var parent = (ConfigurationElementCollection)parentElement;
394 base.PrepareSave (parentElement, mode);
396 for (int n=0; n<list.Count; n++) {
397 ConfigurationElement elem = (ConfigurationElement) list [n];
398 object key = GetElementKey (elem);
399 ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
401 elem.PrepareSave (pitem, mode);
405 internal override bool HasValues (ConfigurationElement parentElement, ConfigurationSaveMode mode)
407 var parent = (ConfigurationElementCollection)parentElement;
409 if (mode == ConfigurationSaveMode.Full)
410 return list.Count > 0;
412 for (int n=0; n<list.Count; n++) {
413 ConfigurationElement elem = (ConfigurationElement) list [n];
414 object key = GetElementKey (elem);
415 ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
417 if (elem.HasValues (pitem, mode))
424 protected internal override void Reset (ConfigurationElement parentElement)
426 bool basic = IsBasic;
428 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
429 for (int n=0; n<parent.Count; n++)
431 ConfigurationElement parentItem = parent.BaseGet (n);
432 ConfigurationElement item = CreateNewElementInternal (null);
433 item.Reset (parentItem);
437 if (inherited == null)
438 inherited = new ArrayList ();
439 inherited.Add (item);
443 inheritedLimitIndex = 0;
445 inheritedLimitIndex = Count - 1;
449 protected internal override void ResetModified ()
452 for (int n=0; n<list.Count; n++) {
453 ConfigurationElement elem = (ConfigurationElement) list [n];
454 elem.ResetModified ();
459 protected internal override void SetReadOnly ()
464 protected internal override bool SerializeElement (XmlWriter writer, bool serializeCollectionKey)
466 if (serializeCollectionKey) {
467 return base.SerializeElement (writer, serializeCollectionKey);
470 bool wroteData = false;
474 for (int n=0; n<list.Count; n++) {
475 ConfigurationElement elem = (ConfigurationElement) list [n];
476 if (ElementName != string.Empty)
477 wroteData = elem.SerializeToXmlElement (writer, ElementName) || wroteData;
479 wroteData = elem.SerializeElement (writer, false) || wroteData;
485 writer.WriteElementString (clearElementName, "");
489 if (removed != null) {
490 for (int n=0; n<removed.Count; n++) {
491 writer.WriteStartElement (removeElementName);
492 ((ConfigurationElement)removed[n]).SerializeElement (writer, true);
493 writer.WriteEndElement ();
495 wroteData = wroteData || removed.Count > 0;
498 for (int n=0; n<list.Count; n++) {
499 ConfigurationElement elem = (ConfigurationElement) list [n];
500 elem.SerializeToXmlElement (writer, addElementName);
503 wroteData = wroteData || list.Count > 0;
508 protected override bool OnDeserializeUnrecognizedElement (string elementName, XmlReader reader)
512 ConfigurationElement elem = null;
514 if (elementName == ElementName)
515 elem = CreateNewElementInternal (null);
516 if (IsElementName (elementName))
517 elem = CreateNewElementInternal (elementName);
520 elem.DeserializeElement (reader, false);
527 if (elementName == clearElementName) {
528 reader.MoveToContent ();
529 if (reader.MoveToNextAttribute ())
530 throw new ConfigurationErrorsException ("Unrecognized attribute '" + reader.LocalName + "'.");
531 reader.MoveToElement ();
538 else if (elementName == removeElementName) {
539 ConfigurationElement elem = CreateNewElementInternal (null);
540 ConfigurationRemoveElement removeElem = new ConfigurationRemoveElement (elem, this);
541 removeElem.DeserializeElement (reader, true);
542 BaseRemove (removeElem.KeyValue);
546 else if (elementName == addElementName) {
547 ConfigurationElement elem = CreateNewElementInternal (null);
548 elem.DeserializeElement (reader, false);
558 protected internal override void Unmerge (ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode updateMode)
560 ConfigurationElementCollection source = (ConfigurationElementCollection) sourceElement;
561 ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement;
563 for (int n=0; n<source.Count; n++) {
564 ConfigurationElement sitem = source.BaseGet (n);
565 object key = source.GetElementKey (sitem);
566 ConfigurationElement pitem = parent != null ? parent.BaseGet (key) as ConfigurationElement : null;
567 ConfigurationElement nitem = CreateNewElementInternal (null);
568 if (pitem != null && updateMode != ConfigurationSaveMode.Full) {
569 nitem.Unmerge (sitem, pitem, updateMode);
570 if (nitem.HasValues (pitem, updateMode))
573 nitem.Unmerge (sitem, null, ConfigurationSaveMode.Full);
578 if (updateMode == ConfigurationSaveMode.Full)
580 else if (parent != null) {
581 for (int n=0; n<parent.Count; n++) {
582 ConfigurationElement pitem = parent.BaseGet (n);
583 object key = parent.GetElementKey (pitem);
584 if (source.IndexOfKey (key) == -1) {
585 if (removed == null) removed = new ArrayList ();
592 #endregion // Methods