// // System.Configuration.ConfigurationElementCollection.cs // // Authors: // Tim Coleman (tim@timcoleman.com) // Martin Baulig // // Copyright (C) Tim Coleman, 2004 // Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // Copyright (C) 2004 Novell, Inc (http://www.novell.com) // using System.Collections; using System.Diagnostics; using System.Xml; namespace System.Configuration { [DebuggerDisplayAttribute ("Count = {Count}")] public abstract partial class ConfigurationElementCollection : ConfigurationElement, ICollection, IEnumerable { ArrayList list = new ArrayList (); ArrayList removed; ArrayList inherited; bool emitClear; bool modified; IComparer comparer; int inheritedLimitIndex; string addElementName = "add"; string clearElementName = "clear"; string removeElementName = "remove"; #region Constructors protected ConfigurationElementCollection () { } protected ConfigurationElementCollection (IComparer comparer) { this.comparer = comparer; } internal override void InitFromProperty (PropertyInformation propertyInfo) { ConfigurationCollectionAttribute colat = propertyInfo.Property.CollectionAttribute; if (colat == null) colat = Attribute.GetCustomAttribute (propertyInfo.Type, typeof (ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute; if (colat != null) { addElementName = colat.AddItemName; clearElementName = colat.ClearItemsName; removeElementName = colat.RemoveItemName; } base.InitFromProperty (propertyInfo); } #endregion // Constructors #region Properties public virtual ConfigurationElementCollectionType CollectionType { get { return ConfigurationElementCollectionType.AddRemoveClearMap; } } bool IsBasic { get { return CollectionType == ConfigurationElementCollectionType.BasicMap || CollectionType == ConfigurationElementCollectionType.BasicMapAlternate; } } bool IsAlternate { get { return CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate || CollectionType == ConfigurationElementCollectionType.BasicMapAlternate; } } public int Count { get { return list.Count; } } protected virtual string ElementName { get { return string.Empty; } } public bool EmitClear { get { return emitClear; } set { emitClear = value; } } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return this; } } protected virtual bool ThrowOnDuplicate { get { if (CollectionType != ConfigurationElementCollectionType.AddRemoveClearMap && CollectionType != ConfigurationElementCollectionType.AddRemoveClearMapAlternate) return false; return true; } } protected internal string AddElementName { get { return addElementName; } set { addElementName = value; } } protected internal string ClearElementName { get { return clearElementName; } set { clearElementName = value; } } protected internal string RemoveElementName { get { return removeElementName; } set { removeElementName = value; } } #endregion // Properties #region Methods protected virtual void BaseAdd (ConfigurationElement element) { BaseAdd (element, ThrowOnDuplicate); } protected void BaseAdd (ConfigurationElement element, bool throwIfExists) { if (IsReadOnly ()) throw new ConfigurationErrorsException ("Collection is read only."); if (IsAlternate) { list.Insert (inheritedLimitIndex, element); inheritedLimitIndex++; } else { int old_index = IndexOfKey (GetElementKey (element)); if (old_index >= 0) { if (element.Equals (list [old_index])) return; if (throwIfExists) throw new ConfigurationErrorsException ("Duplicate element in collection"); list.RemoveAt (old_index); } list.Add (element); } modified = true; } protected virtual void BaseAdd (int index, ConfigurationElement element) { if (ThrowOnDuplicate && BaseIndexOf (element) != -1) throw new ConfigurationErrorsException ("Duplicate element in collection"); if (IsReadOnly ()) throw new ConfigurationErrorsException ("Collection is read only."); if (IsAlternate && (index > inheritedLimitIndex)) throw new ConfigurationErrorsException ("Can't insert new elements below the inherited elements."); if (!IsAlternate && (index <= inheritedLimitIndex)) throw new ConfigurationErrorsException ("Can't insert new elements above the inherited elements."); list.Insert (index, element); modified = true; } protected internal void BaseClear () { if (IsReadOnly ()) throw new ConfigurationErrorsException ("Collection is read only."); list.Clear (); modified = true; } protected internal ConfigurationElement BaseGet (int index) { return (ConfigurationElement) list [index]; } protected internal ConfigurationElement BaseGet (object key) { int index = IndexOfKey (key); if (index != -1) return (ConfigurationElement) list [index]; else return null; } protected internal object[] BaseGetAllKeys () { object[] keys = new object [list.Count]; for (int n=0; n= list.Count) throw new ConfigurationErrorsException (String.Format ("Index {0} is out of range", index)); return GetElementKey ((ConfigurationElement) list[index]).ToString (); } protected int BaseIndexOf (ConfigurationElement element) { return list.IndexOf (element); } int IndexOfKey (object key) { for (int n=0; n 0) inheritedLimitIndex--; } modified = true; } bool CompareKeys (object key1, object key2) { if (comparer != null) return comparer.Compare (key1, key2) == 0; else return object.Equals (key1, key2); } public void CopyTo (ConfigurationElement[] array, int index) { list.CopyTo (array, index); } protected abstract ConfigurationElement CreateNewElement (); protected virtual ConfigurationElement CreateNewElement (string elementName) { return CreateNewElement (); } ConfigurationElement CreateNewElementInternal (string elementName) { ConfigurationElement elem; if (elementName == null) elem = CreateNewElement (); else elem = CreateNewElement (elementName); elem.Init (); return elem; } public override bool Equals (object compareTo) { ConfigurationElementCollection other = compareTo as ConfigurationElementCollection; if (other == null) return false; if (GetType() != other.GetType()) return false; if (Count != other.Count) return false; for (int n=0; n 0; for (int n=0; n 0; } for (int n=0; n 0; } return wroteData; } protected override bool OnDeserializeUnrecognizedElement (string elementName, XmlReader reader) { if (IsBasic) { ConfigurationElement elem = null; if (elementName == ElementName) elem = CreateNewElementInternal (null); if (IsElementName (elementName)) elem = CreateNewElementInternal (elementName); if (elem != null) { elem.DeserializeElement (reader, false); BaseAdd (elem); modified = false; return true; } } else { if (elementName == clearElementName) { reader.MoveToContent (); if (reader.MoveToNextAttribute ()) throw new ConfigurationErrorsException ("Unrecognized attribute '" + reader.LocalName + "'."); reader.MoveToElement (); reader.Skip (); BaseClear (); emitClear = true; modified = false; return true; } else if (elementName == removeElementName) { ConfigurationElement elem = CreateNewElementInternal (null); ConfigurationRemoveElement removeElem = new ConfigurationRemoveElement (elem, this); removeElem.DeserializeElement (reader, true); BaseRemove (removeElem.KeyValue); modified = false; return true; } else if (elementName == addElementName) { ConfigurationElement elem = CreateNewElementInternal (null); elem.DeserializeElement (reader, false); BaseAdd (elem); modified = false; return true; } } return false; } protected internal override void Unmerge (ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode updateMode) { ConfigurationElementCollection source = (ConfigurationElementCollection) sourceElement; ConfigurationElementCollection parent = (ConfigurationElementCollection) parentElement; for (int n=0; n