The Labs \ Source Viewer \ SSCLI \ System.Configuration \ InheritedType

  1. //------------------------------------------------------------------------------
  2. // <copyright file="ConfigurationElementCollection.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Specialized;
  18. using System.Xml;
  19. namespace System.Configuration
  20. {
  21.    
  22.     [System.Diagnostics.DebuggerDisplay("Count = {Count}")]
  23.     public abstract class ConfigurationElementCollection : ConfigurationElement, ICollection
  24.     {
  25.         internal const string DefaultAddItemName = "add";
  26.         internal const string DefaultRemoveItemName = "remove";
  27.         internal const string DefaultClearItemsName = "clear";
  28.        
  29.         private int _removedItemCount = 0;
  30.         // Number of items removed for this collection (not including parent)
  31.         private int _inheritedCount = 0;
  32.         // Total number of inherited items
  33.         private ArrayList _items = new ArrayList();
  34.         private string _addElement = DefaultAddItemName;
  35.         private string _removeElement = DefaultRemoveItemName;
  36.         private string _clearElement = DefaultClearItemsName;
  37.         private bool bEmitClearTag = false;
  38.         private bool bCollectionCleared = false;
  39.         private bool bModified = false;
  40.         private bool bReadOnly = false;
  41.         private IComparer _comparer;
  42.         internal bool internalAddToEnd = false;
  43.         internal string internalElementTagName = string.Empty;
  44.        
  45.         protected ConfigurationElementCollection()
  46.         {
  47.         }
  48.        
  49.         protected ConfigurationElementCollection(IComparer comparer)
  50.         {
  51.             if (comparer == null) {
  52.                 throw new ArgumentNullException("comparer");
  53.             }
  54.            
  55.             _comparer = comparer;
  56.         }
  57.        
  58.         private ArrayList Items {
  59.             get { return _items; }
  60.         }
  61.        
  62.         private enum InheritedType
  63.         {
  64.             inNeither = 0,
  65.             inParent = 1,
  66.             inSelf = 2,
  67.             inBothSame = 3,
  68.             inBothDiff = 4,
  69.             inBothCopyNoRemove = 5
  70.         }
  71.        
  72.         protected internal string AddElementName {
  73.             get { return _addElement; }
  74.             set {
  75.                 _addElement = value;
  76.                 if (BaseConfigurationRecord.IsReservedAttributeName(value)) {
  77.                     throw new ArgumentException(SR.GetString(SR.Item_name_reserved, DefaultAddItemName, value));
  78.                 }
  79.             }
  80.         }
  81.        
  82.         protected internal string RemoveElementName {
  83.             get { return _removeElement; }
  84.             set {
  85.                 if (BaseConfigurationRecord.IsReservedAttributeName(value)) {
  86.                     throw new ArgumentException(SR.GetString(SR.Item_name_reserved, DefaultRemoveItemName, value));
  87.                 }
  88.                 _removeElement = value;
  89.             }
  90.         }
  91.        
  92.         protected internal string ClearElementName {
  93.             get { return _clearElement; }
  94.             set {
  95.                 if (BaseConfigurationRecord.IsReservedAttributeName(value)) {
  96.                     throw new ArgumentException(SR.GetString(SR.Item_name_reserved, DefaultClearItemsName, value));
  97.                 }
  98.                 _clearElement = value;
  99.             }
  100.         }
  101.        
  102.         // AssociateContext
  103.         //
  104.         // Associate a collection of values with a configRecord
  105.         //
  106.         internal override void AssociateContext(BaseConfigurationRecord configRecord)
  107.         {
  108.             base.AssociateContext(configRecord);
  109.            
  110.             foreach (Entry entry in _items) {
  111.                 if (entry._value != null) {
  112.                     entry._value.AssociateContext(configRecord);
  113.                 }
  114.             }
  115.         }
  116.        
  117.         protected internal override bool IsModified()
  118.         {
  119.             if (bModified == true) {
  120.                 return true;
  121.             }
  122.            
  123.             if (base.IsModified() == true) {
  124.                 return true;
  125.             }
  126.            
  127.             foreach (Entry entry in _items) {
  128.                 if (entry._entryType != EntryType.Removed) {
  129.                     ConfigurationElement elem = entry._value;
  130.                     if (elem.IsModified()) {
  131.                         return true;
  132.                     }
  133.                 }
  134.             }
  135.             return false;
  136.         }
  137.        
  138.         protected internal override void ResetModified()
  139.         {
  140.             bModified = false;
  141.             base.ResetModified();
  142.            
  143.             foreach (Entry entry in _items) {
  144.                 if (entry._entryType != EntryType.Removed) {
  145.                     ConfigurationElement elem = entry._value;
  146.                     elem.ResetModified();
  147.                 }
  148.             }
  149.         }
  150.        
  151.         public override bool IsReadOnly()
  152.         {
  153.             return bReadOnly;
  154.         }
  155.        
  156.         protected internal override void SetReadOnly()
  157.         {
  158.             bReadOnly = true;
  159.             foreach (Entry entry in _items) {
  160.                 if (entry._entryType != EntryType.Removed) {
  161.                     ConfigurationElement elem = entry._value;
  162.                     elem.SetReadOnly();
  163.                 }
  164.             }
  165.         }
  166.        
  167.         internal virtual IEnumerator GetEnumeratorImpl()
  168.         {
  169.             return new Enumerator(_items, this);
  170.         }
  171.        
  172.         internal IEnumerator GetElementsEnumerator()
  173.         {
  174.             // Return an enumerator over the collection's config elements.
  175.             // This is different then the std GetEnumerator because the second one
  176.             // can return different set of items if overriden in a derived class
  177.            
  178.             return new Enumerator(_items, this);
  179.         }
  180.        
  181.         public override bool Equals(object compareTo)
  182.         {
  183.             if (compareTo.GetType() == this.GetType()) {
  184.                 ConfigurationElementCollection compareToElem = (ConfigurationElementCollection)compareTo;
  185.                 if (this.Count != compareToElem.Count) {
  186.                     return false;
  187.                 }
  188.                
  189.                 foreach (Entry thisEntry in Items) {
  190.                     bool found = false;
  191.                     foreach (Entry compareEntry in compareToElem.Items) {
  192.                         if (Object.Equals(thisEntry._value, compareEntry._value)) {
  193.                             found = true;
  194.                             break;
  195.                         }
  196.                     }
  197.                     if (found == false) {
  198.                         // not in the collection must be different
  199.                         return false;
  200.                     }
  201.                 }
  202.                 return true;
  203.             }
  204.             return false;
  205.         }
  206.        
  207.         public override int GetHashCode()
  208.         {
  209.             int hHashCode = 0;
  210.             foreach (Entry thisEntry in Items) {
  211.                 ConfigurationElement elem = thisEntry._value;
  212.                 hHashCode ^= elem.GetHashCode();
  213.             }
  214.             return hHashCode;
  215.         }
  216.        
  217.        
  218.         protected internal override void Unmerge(ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode saveMode)
  219.         {
  220.            
  221.             base.Unmerge(sourceElement, parentElement, saveMode);
  222.             if (sourceElement != null) {
  223.                 ConfigurationElementCollection parentCollection = parentElement as ConfigurationElementCollection;
  224.                 ConfigurationElementCollection sourceCollection = sourceElement as ConfigurationElementCollection;
  225.                 Hashtable Inheritance = new Hashtable();
  226.                 _lockedAllExceptAttributesList = sourceElement._lockedAllExceptAttributesList;
  227.                 _lockedAllExceptElementsList = sourceElement._lockedAllExceptElementsList;
  228.                 _fItemLocked = sourceElement._fItemLocked;
  229.                 _lockedAttributesList = sourceElement._lockedAttributesList;
  230.                 _lockedElementsList = sourceElement._lockedElementsList;
  231.                
  232.                 AssociateContext(sourceElement._configRecord);
  233.                
  234.                 if (parentElement != null) {
  235.                     if (parentElement._lockedAttributesList != null)
  236.                         _lockedAttributesList = UnMergeLockList(sourceElement._lockedAttributesList, parentElement._lockedAttributesList, saveMode);
  237.                     if (parentElement._lockedElementsList != null)
  238.                         _lockedElementsList = UnMergeLockList(sourceElement._lockedElementsList, parentElement._lockedElementsList, saveMode);
  239.                     if (parentElement._lockedAllExceptAttributesList != null)
  240.                         _lockedAllExceptAttributesList = UnMergeLockList(sourceElement._lockedAllExceptAttributesList, parentElement._lockedAllExceptAttributesList, saveMode);
  241.                     if (parentElement._lockedAllExceptElementsList != null)
  242.                         _lockedAllExceptElementsList = UnMergeLockList(sourceElement._lockedAllExceptElementsList, parentElement._lockedAllExceptElementsList, saveMode);
  243.                 }
  244.                
  245.                 if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap || CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  246.                     // When writing out portable configurations the <clear/> tag should be written
  247.                     bCollectionCleared = sourceCollection.bCollectionCleared;
  248.                     EmitClear = (saveMode == ConfigurationSaveMode.Full && (_clearElement.Length != 0)) || (saveMode == ConfigurationSaveMode.Modified && bCollectionCleared) ? true : sourceCollection.EmitClear;
  249.                    
  250.                     if ((parentCollection != null) && (EmitClear != true)) {
  251.                         foreach (Entry entry in parentCollection.Items) {
  252.                             if (entry._entryType != EntryType.Removed) {
  253.                                 Inheritance[entry.GetKey(this)] = InheritedType.inParent;
  254.                             }
  255.                         }
  256.                     }
  257.                    
  258.                     foreach (Entry entry in sourceCollection.Items) {
  259.                         if (entry._entryType != EntryType.Removed) {
  260.                             if (Inheritance.Contains(entry.GetKey(this))) {
  261.                                 Entry parentEntry = (Entry)parentCollection.Items[parentCollection.RealIndexOf(entry._value)];
  262.                                
  263.                                 ConfigurationElement elem = entry._value;
  264.                                 if (elem.Equals(parentEntry._value)) {
  265.                                     Inheritance[entry.GetKey(this)] = InheritedType.inBothSame;
  266.                                     if (saveMode == ConfigurationSaveMode.Modified) {
  267.                                         if (elem.IsModified()) {
  268.                                             Inheritance[entry.GetKey(this)] = InheritedType.inBothDiff;
  269.                                         }
  270.                                         else if (elem.ElementPresent) {
  271.                                             // This is when the source file contained the entry but it was an
  272.                                             // exact copy. We don't want to emit a remove so we treat it as
  273.                                             // a special case.
  274.                                             Inheritance[entry.GetKey(this)] = InheritedType.inBothCopyNoRemove;
  275.                                         }
  276.                                     }
  277.                                 }
  278.                                 else {
  279.                                     Inheritance[entry.GetKey(this)] = InheritedType.inBothDiff;
  280.                                     if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate && entry._entryType == EntryType.Added) {
  281.                                         // this is a special case for deailing with defect number 529517
  282.                                         // this code allow the config to write out the same xml when no remove was
  283.                                         // present during deserialization.
  284.                                         Inheritance[entry.GetKey(this)] = InheritedType.inBothCopyNoRemove;
  285.                                     }
  286.                                 }
  287.                             }
  288.                             else {
  289.                                 // not in parent
  290.                                 Inheritance[entry.GetKey(this)] = InheritedType.inSelf;
  291.                             }
  292.                         }
  293.                     }
  294.                    
  295.                     //
  296.                     if ((parentCollection != null) && (EmitClear != true)) {
  297.                         foreach (Entry entry in parentCollection.Items) {
  298.                             if (entry._entryType != EntryType.Removed) {
  299.                                
  300.                                 InheritedType tp = (InheritedType)Inheritance[entry.GetKey(this)];
  301.                                 if (tp == InheritedType.inParent || tp == InheritedType.inBothDiff) {
  302.                                     ConfigurationElement elem = CallCreateNewElement(entry.GetKey(this).ToString());
  303.                                    
  304.                                     elem.Reset(entry._value);
  305.                                     // copy this entry
  306.                                     BaseAdd(elem, ThrowOnDuplicate, true);
  307.                                     // Add it (so that is once existed in the temp
  308.                                     BaseRemove(entry.GetKey(this), false);
  309.                                     // now remove it to for a remove instruction
  310.                                 }
  311.                             }
  312.                         }
  313.                     }
  314.                    
  315.                     foreach (Entry entry in sourceCollection.Items) {
  316.                         if (entry._entryType != EntryType.Removed) {
  317.                             InheritedType tp = (InheritedType)Inheritance[entry.GetKey(this)];
  318.                            
  319.                             if (tp == InheritedType.inSelf || tp == InheritedType.inBothDiff || tp == InheritedType.inBothCopyNoRemove) {
  320.                                 ConfigurationElement elem = CallCreateNewElement(entry.GetKey(this).ToString());
  321.                                
  322.                                 elem.Unmerge(entry._value, null, saveMode);
  323.                                
  324.                                 if (tp == InheritedType.inSelf) {
  325.                                     elem.RemoveAllInheritedLocks();
  326.                                     // If the key changed only local locks are kept
  327.                                 }
  328.                                
  329.                                 BaseAdd(elem, ThrowOnDuplicate, true);
  330.                                 // Add it
  331.                             }
  332.                         }
  333.                     }
  334.                 }
  335.                 else {
  336.                     if (CollectionType == ConfigurationElementCollectionType.BasicMap || CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) {
  337.                         foreach (Entry entry in sourceCollection.Items) {
  338.                             bool FoundKeyInParent = false;
  339.                             Entry parentEntrySaved = null;
  340.                            
  341.                             if (entry._entryType == EntryType.Added || entry._entryType == EntryType.Replaced) {
  342.                                 bool InParent = false;
  343.                                
  344.                                 if (parentCollection != null) {
  345.                                     foreach (Entry parentEntry in parentCollection.Items) {
  346.                                         if (Object.Equals(entry.GetKey(this), parentEntry.GetKey(this))) {
  347.                                             // for basic map collection where the key is actually an element
  348.                                             // we do not want the merging behavior or data will not get written
  349.                                             // out for the properties if they match the first element deamed to be a parent
  350.                                             // For example <allow verbs="NewVerb" users="*"/> will loose the users because
  351.                                             // an entry exists in the root element.
  352.                                             if (!IsElementName(entry.GetKey(this).ToString())) {
  353.                                                 // For elements which are not keyed by the element name
  354.                                                 // need to be unmerged
  355.                                                 FoundKeyInParent = true;
  356.                                                 parentEntrySaved = parentEntry;
  357.                                             }
  358.                                         }
  359.                                        
  360.                                         if (Object.Equals(entry._value, parentEntry._value)) {
  361.                                             FoundKeyInParent = true;
  362.                                             InParent = true;
  363.                                             // in parent and the same exact values
  364.                                             parentEntrySaved = parentEntry;
  365.                                             break;
  366.                                         }
  367.                                     }
  368.                                 }
  369.                                
  370.                                 ConfigurationElement elem = CallCreateNewElement(entry.GetKey(this).ToString());
  371.                                
  372.                                 if (!FoundKeyInParent) {
  373.                                     // Unmerge is similar to a reset when used like this
  374.                                     // except that it handles the different update modes
  375.                                     // which Reset does not understand
  376.                                     elem.Unmerge(entry._value, null, saveMode);
  377.                                     // copy this entry
  378.                                     BaseAdd(-1, elem, true);
  379.                                     // Add it
  380.                                 }
  381.                                 else {
  382.                                     ConfigurationElement sourceItem = entry._value;
  383.                                     if (!InParent || (saveMode == ConfigurationSaveMode.Modified && sourceItem.IsModified()) || (saveMode == ConfigurationSaveMode.Full)) {
  384.                                         elem.Unmerge(entry._value, parentEntrySaved._value, saveMode);
  385.                                         BaseAdd(-1, elem, true);
  386.                                         // Add it
  387.                                     }
  388.                                 }
  389.                             }
  390.                         }
  391.                     }
  392.                 }
  393.             }
  394.         }
  395.        
  396.         protected internal override void Reset(ConfigurationElement parentElement)
  397.         {
  398.             ConfigurationElementCollection parentCollection = parentElement as ConfigurationElementCollection;
  399.             ResetLockLists(parentElement);
  400.            
  401.             if (parentCollection != null) {
  402.                 foreach (Entry entry in parentCollection.Items) {
  403.                     ConfigurationElement elem = CallCreateNewElement(entry.GetKey(this).ToString());
  404.                     elem.Reset(entry._value);
  405.                    
  406.                     if ((CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap || CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) && (entry._entryType == EntryType.Added || entry._entryType == EntryType.Replaced)) {
  407.                         // do not add removed items from the parent
  408.                         BaseAdd(elem, true, true);
  409.                         // This version combines dups and throws (unless overridden)
  410.                     }
  411.                     else {
  412.                         if (CollectionType == ConfigurationElementCollectionType.BasicMap || CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) {
  413.                             BaseAdd(-1, elem, true);
  414.                             // this version appends regardless of if it is a dup.
  415.                         }
  416.                     }
  417.                 }
  418.                 _inheritedCount = Count;
  419.                 // After reset the count is the number of items actually inherited.
  420.             }
  421.         }
  422.        
  423.         public int Count {
  424.             get { return _items.Count - _removedItemCount; }
  425.         }
  426.        
  427.         public bool EmitClear {
  428.             get { return bEmitClearTag; }
  429.             set {
  430.                 if (IsReadOnly()) {
  431.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
  432.                 }
  433.                 if (value == true) {
  434.                     CheckLockedElement(_clearElement, null);
  435.                     // has clear been locked?
  436.                     CheckLockedElement(_removeElement, null);
  437.                     // has remove been locked? Clear implies remove
  438.                 }
  439.                 bModified = true;
  440.                 bEmitClearTag = value;
  441.             }
  442.         }
  443.        
  444.         public bool IsSynchronized {
  445.             get { return false; }
  446.         }
  447.        
  448.         public object SyncRoot {
  449.             get { return null; }
  450.         }
  451.        
  452.         public void CopyTo(ConfigurationElement[] array, int index)
  453.         {
  454.             ((ICollection)this).CopyTo(array, index);
  455.         }
  456.        
  457.         void ICollection.CopyTo(Array arr, int index)
  458.         {
  459.             foreach (Entry entry in _items) {
  460.                 if (entry._entryType != EntryType.Removed) {
  461.                     arr.SetValue(entry._value, index++);
  462.                 }
  463.             }
  464.         }
  465.        
  466.         public IEnumerator GetEnumerator()
  467.         {
  468.             return GetEnumeratorImpl();
  469.         }
  470.        
  471.         protected virtual void BaseAdd(ConfigurationElement element)
  472.         {
  473.             BaseAdd(element, ThrowOnDuplicate);
  474.         }
  475.        
  476.         protected internal void BaseAdd(ConfigurationElement element, bool throwIfExists)
  477.         {
  478.             BaseAdd(element, throwIfExists, false);
  479.         }
  480.        
  481.         private void BaseAdd(ConfigurationElement element, bool throwIfExists, bool ignoreLocks)
  482.         {
  483.             bool flagAsReplaced = false;
  484.             bool localAddToEnd = internalAddToEnd;
  485.            
  486.             if (IsReadOnly()) {
  487.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
  488.             }
  489.            
  490.             if (LockItem == true && ignoreLocks == false) {
  491.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_element_locked, _addElement));
  492.             }
  493.            
  494.             object key = GetElementKeyInternal(element);
  495.             int iFoundItem = -1;
  496.             for (int index = 0; index < _items.Count; index++) {
  497.                 Entry entry = (Entry)_items[index];
  498.                 if (CompareKeys(key, entry.GetKey(this))) {
  499.                     if (entry._value != null && entry._value.LockItem == true && ignoreLocks == false) {
  500.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_item_locked));
  501.                     }
  502.                     if (entry._entryType != EntryType.Removed && throwIfExists) {
  503.                         if (!element.Equals(entry._value)) {
  504.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_already_exists, key), element.PropertyFileName(""), element.PropertyLineNumber(""));
  505.                         }
  506.                         else {
  507.                             entry._value = element;
  508.                         }
  509.                         return;
  510.                     }
  511.                     if (entry._entryType != EntryType.Added) {
  512.                         if ((CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap || CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) && entry._entryType == EntryType.Removed && _removedItemCount > 0) {
  513.                             _removedItemCount--;
  514.                             // account for the value
  515.                         }
  516.                         entry._entryType = EntryType.Replaced;
  517.                         flagAsReplaced = true;
  518.                     }
  519.                     if (localAddToEnd || CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  520.                         iFoundItem = index;
  521.                         if (entry._entryType == EntryType.Added) {
  522.                             localAddToEnd = true;
  523.                         }
  524.                         break;
  525.                     }
  526.                     else {
  527.                         // check to see if the element is trying to set a locked property.
  528.                         if (ignoreLocks == false) {
  529.                             element.HandleLockedAttributes(entry._value);
  530.                             // copy the lock from the removed element before setting the new element
  531.                             element.MergeLocks(entry._value);
  532.                         }
  533.                         entry._value = element;
  534.                         bModified = true;
  535.                         return;
  536.                     }
  537.                 }
  538.             }
  539.            
  540.             // Brand new item.
  541.             if (iFoundItem >= 0) {
  542.                 _items.RemoveAt(iFoundItem);
  543.                
  544.                 // if the item being removed was inherited adjust the cout
  545.                 if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate && iFoundItem > Count + _removedItemCount - _inheritedCount) {
  546.                     _inheritedCount--;
  547.                 }
  548.             }
  549.             BaseAddInternal(localAddToEnd ? -1 : iFoundItem, element, flagAsReplaced, ignoreLocks);
  550.             bModified = true;
  551.         }
  552.        
  553.         protected int BaseIndexOf(ConfigurationElement element)
  554.         {
  555.             int index = 0;
  556.             object key = GetElementKeyInternal(element);
  557.             foreach (Entry entry in _items) {
  558.                 if (entry._entryType != EntryType.Removed) {
  559.                     if (CompareKeys(key, entry.GetKey(this))) {
  560.                         return index;
  561.                     }
  562.                     index++;
  563.                 }
  564.             }
  565.             return -1;
  566.         }
  567.        
  568.         internal int RealIndexOf(ConfigurationElement element)
  569.         {
  570.             int index = 0;
  571.             object key = GetElementKeyInternal(element);
  572.             foreach (Entry entry in _items) {
  573.                 if (CompareKeys(key, entry.GetKey(this))) {
  574.                     return index;
  575.                 }
  576.                 index++;
  577.             }
  578.             return -1;
  579.         }
  580.        
  581.         private void BaseAddInternal(int index, ConfigurationElement element, bool flagAsReplaced, bool ignoreLocks)
  582.         {
  583.             // Allow the element to initialize itself after its
  584.             // constructor has been run so that it may access
  585.             // virtual methods.
  586.            
  587.             element.AssociateContext(_configRecord);
  588.             if (element != null) {
  589.                 element.CallInit();
  590.             }
  591.            
  592.             if (IsReadOnly()) {
  593.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
  594.             }
  595.            
  596.             if (!ignoreLocks) {
  597.                 // during reset we ignore locks so we can copy the elements
  598.                 if (CollectionType == ConfigurationElementCollectionType.BasicMap || CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) {
  599.                     if (BaseConfigurationRecord.IsReservedAttributeName(ElementName)) {
  600.                         throw new ArgumentException(SR.GetString(SR.Basicmap_item_name_reserved, ElementName));
  601.                     }
  602.                     CheckLockedElement(ElementName, null);
  603.                 }
  604.                 if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap || CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  605.                    
  606.                     CheckLockedElement(_addElement, null);
  607.                 }
  608.             }
  609.            
  610.             if (CollectionType == ConfigurationElementCollectionType.BasicMapAlternate || CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  611.                 if (index == -1) {
  612.                     index = Count + _removedItemCount - _inheritedCount;
  613.                     // insert before inherited, but after any removed
  614.                 }
  615.                 else {
  616.                     if (index > Count + _removedItemCount - _inheritedCount && flagAsReplaced == false) {
  617.                         throw (new ConfigurationErrorsException(SR.GetString(SR.Config_base_cannot_add_items_below_inherited_items)));
  618.                     }
  619.                 }
  620.             }
  621.            
  622.             if (CollectionType == ConfigurationElementCollectionType.BasicMap && index >= 0 && index < _inheritedCount) {
  623.                 throw (new ConfigurationErrorsException(SR.GetString(SR.Config_base_cannot_add_items_above_inherited_items)));
  624.             }
  625.            
  626.             EntryType entryType = (flagAsReplaced == false) ? EntryType.Added : EntryType.Replaced;
  627.            
  628.             object key = GetElementKeyInternal(element);
  629.            
  630.             if (index >= 0) {
  631.                 if (index > _items.Count) {
  632.                     throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
  633.                 }
  634.                 _items.Insert(index, new Entry(entryType, key, element));
  635.             }
  636.             else {
  637.                 _items.Add(new Entry(entryType, key, element));
  638.             }
  639.            
  640.             bModified = true;
  641.         }
  642.        
  643.        
  644.         protected virtual void BaseAdd(int index, ConfigurationElement element)
  645.         {
  646.             BaseAdd(index, element, false);
  647.         }
  648.        
  649.         private void BaseAdd(int index, ConfigurationElement element, bool ignoreLocks)
  650.         {
  651.             if (IsReadOnly()) {
  652.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
  653.             }
  654.             if (index < -1) {
  655.                 throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
  656.             }
  657.            
  658.             if ((index != -1) && (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap || CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate)) {
  659.                
  660.                 // If it's an AddRemoveClearMap*** collection, turn the index passed into into a real internal index
  661.                 int realIndex = 0;
  662.                
  663.                 if (index > 0) {
  664.                     foreach (Entry entryfound in _items) {
  665.                         if (entryfound._entryType != EntryType.Removed) {
  666.                             index--;
  667.                         }
  668.                         if (index == 0) {
  669.                             break;
  670.                         }
  671.                         realIndex++;
  672.                     }
  673.                     index = ++realIndex;
  674.                 }
  675.                 // check for duplicates
  676.                 object key = GetElementKeyInternal(element);
  677.                 foreach (Entry entry in _items) {
  678.                     if (CompareKeys(key, entry.GetKey(this))) {
  679.                         if (entry._entryType != EntryType.Removed) {
  680.                             if (!element.Equals(entry._value)) {
  681.                                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_already_exists, key), element.PropertyFileName(""), element.PropertyLineNumber(""));
  682.                             }
  683.                             return;
  684.                         }
  685.                     }
  686.                 }
  687.                
  688.             }
  689.            
  690.             BaseAddInternal(index, element, false, ignoreLocks);
  691.         }
  692.        
  693.         protected internal void BaseRemove(object key)
  694.         {
  695.             BaseRemove(key, false);
  696.         }
  697.        
  698.         private void BaseRemove(object key, bool throwIfMissing)
  699.         {
  700.             if (IsReadOnly())
  701.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
  702.            
  703.            
  704.             int index = 0;
  705.             bool foundEntry = false;
  706.             foreach (Entry entry in _items) {
  707.                 if (CompareKeys(key, entry.GetKey(this))) {
  708.                     foundEntry = true;
  709.                    
  710.                     // A phoney delete is already present
  711.                     if (entry._value == null) {
  712.                         if (throwIfMissing) {
  713.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_not_found, key));
  714.                         }
  715.                         else {
  716.                             return;
  717.                         }
  718.                     }
  719.                    
  720.                     if (entry._value.LockItem == true) {
  721.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, key));
  722.                     }
  723.                    
  724.                     if (entry._value.ElementPresent == false) {
  725.                         CheckLockedElement(_removeElement, null);
  726.                         // has remove been locked?
  727.                     }
  728.                    
  729.                     switch (entry._entryType) {
  730.                         case EntryType.Added:
  731.                             if (CollectionType != ConfigurationElementCollectionType.AddRemoveClearMap && CollectionType != ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  732.                                 if (CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) {
  733.                                     if (index >= Count - _inheritedCount) {
  734.                                         throw (new ConfigurationErrorsException(SR.GetString(SR.Config_base_cannot_remove_inherited_items)));
  735.                                     }
  736.                                 }
  737.                                 if (CollectionType == ConfigurationElementCollectionType.BasicMap) {
  738.                                     if (index < _inheritedCount) {
  739.                                         throw (new ConfigurationErrorsException(SR.GetString(SR.Config_base_cannot_remove_inherited_items)));
  740.                                     }
  741.                                 }
  742.                                
  743.                                 _items.RemoveAt(index);
  744.                             }
  745.                             else {
  746.                                 // don't really remove it from the collection just mark it removed
  747.                                 entry._entryType = EntryType.Removed;
  748.                                 _removedItemCount++;
  749.                             }
  750.                             break;
  751.                         case EntryType.Removed:
  752.                             if (throwIfMissing) {
  753.                                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_already_removed));
  754.                             }
  755.                             break;
  756.                         default:
  757.                             if (CollectionType != ConfigurationElementCollectionType.AddRemoveClearMap && CollectionType != ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  758.                                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_elements_may_not_be_removed));
  759.                             }
  760.                             entry._entryType = EntryType.Removed;
  761.                             _removedItemCount++;
  762.                             break;
  763.                     }
  764.                     bModified = true;
  765.                     return;
  766.                 }
  767.                 index++;
  768.             }
  769.             // Note because it is possible for removes to get orphaned by the API they will
  770.             // not cause a throw from the base classes. The scenerio is:
  771.             // Add an item in a parent level
  772.             // remove the item in a child level
  773.             // remove the item at the parent level.
  774.             //
  775.             // throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_not_found));
  776.             if (foundEntry == false) {
  777.                 if (throwIfMissing) {
  778.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_not_found, key));
  779.                 }
  780.                
  781.                 if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap || CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  782.                     if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  783.                         _items.Insert(Count + _removedItemCount - _inheritedCount, new Entry(EntryType.Removed, key, null));
  784.                     }
  785.                     else {
  786.                         _items.Add(new Entry(EntryType.Removed, key, null));
  787.                     }
  788.                     _removedItemCount++;
  789.                 }
  790.                
  791.             }
  792.         }
  793.        
  794.         protected internal ConfigurationElement BaseGet(object key)
  795.         {
  796.             foreach (Entry entry in _items) {
  797.                 if (entry._entryType != EntryType.Removed) {
  798.                     if (CompareKeys(key, entry.GetKey(this))) {
  799.                         return entry._value;
  800.                     }
  801.                 }
  802.             }
  803.             return null;
  804.         }
  805.        
  806.         protected internal bool BaseIsRemoved(object key)
  807.         {
  808.             foreach (Entry entry in _items) {
  809.                 if (CompareKeys(key, entry.GetKey(this))) {
  810.                     if (entry._entryType == EntryType.Removed) {
  811.                         return true;
  812.                     }
  813.                     else {
  814.                         return false;
  815.                     }
  816.                 }
  817.             }
  818.             return false;
  819.         }
  820.        
  821.         protected internal ConfigurationElement BaseGet(int index)
  822.         {
  823.             if (index < 0) {
  824.                 throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
  825.             }
  826.            
  827.             int VirtualIndex = 0;
  828.             Entry entry = (Entry)null;
  829.            
  830.             foreach (Entry entryfound in _items) {
  831.                 if (VirtualIndex == index && (entryfound._entryType != EntryType.Removed)) {
  832.                     entry = entryfound;
  833.                     break;
  834.                 }
  835.                 if (entryfound._entryType != EntryType.Removed) {
  836.                     VirtualIndex++;
  837.                 }
  838.             }
  839.            
  840.             if (entry != null) {
  841.                 return entry._value;
  842.             }
  843.             else {
  844.                 throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
  845.             }
  846.         }
  847.        
  848.         protected internal object[] BaseGetAllKeys()
  849.         {
  850.             object[] keys = new object[Count];
  851.             int index = 0;
  852.             foreach (Entry entry in _items) {
  853.                 if (entry._entryType != EntryType.Removed) {
  854.                     keys[index] = entry.GetKey(this);
  855.                     index++;
  856.                 }
  857.             }
  858.             return keys;
  859.         }
  860.        
  861.         protected internal object BaseGetKey(int index)
  862.         {
  863.             int VirtualIndex = 0;
  864.             Entry entry = (Entry)null;
  865.             if (index < 0) {
  866.                 throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
  867.             }
  868.            
  869.             foreach (Entry entryfound in _items) {
  870.                 if (VirtualIndex == index && (entryfound._entryType != EntryType.Removed)) {
  871.                     entry = entryfound;
  872.                     break;
  873.                 }
  874.                
  875.                 if (entryfound._entryType != EntryType.Removed) {
  876.                     VirtualIndex++;
  877.                 }
  878.             }
  879.            
  880.             // Entry entry = (Entry)_items[index];
  881.             if (entry != null) {
  882.                 object key = entry.GetKey(this);
  883.                
  884.                 return key;
  885.             }
  886.             else {
  887.                 throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
  888.             }
  889.         }
  890.        
  891.         protected internal void BaseClear()
  892.         {
  893.             if (IsReadOnly()) {
  894.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
  895.             }
  896.            
  897.             CheckLockedElement(_clearElement, null);
  898.             // has clear been locked?
  899.             CheckLockedElement(_removeElement, null);
  900.             // has remove been locked? Clear implies remove
  901.             bModified = true;
  902.             bCollectionCleared = true;
  903.             if ((CollectionType == ConfigurationElementCollectionType.BasicMap || CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) && _inheritedCount > 0) {
  904.                 int RemoveIndex = 0;
  905.                 if (CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) {
  906.                     RemoveIndex = 0;
  907.                     // Inherited items are at the bottom and cannot be removed
  908.                 }
  909.                 if (CollectionType == ConfigurationElementCollectionType.BasicMap) {
  910.                     RemoveIndex = _inheritedCount;
  911.                     // inherited items are at the top and cannot be removed
  912.                 }
  913.                 while (Count - _inheritedCount > 0) {
  914.                     _items.RemoveAt(RemoveIndex);
  915.                 }
  916.             }
  917.             else {
  918.                 // do not clear any locked items
  919.                 // _items.Clear();
  920.                 int inheritedRemoved = 0;
  921.                 int removedRemoved = 0;
  922.                 int initialCount = Count;
  923.                
  924.                 // check for locks before removing any items from the collection
  925.                 for (int CheckIndex = 0; CheckIndex < _items.Count; CheckIndex++) {
  926.                     Entry entry = (Entry)_items[CheckIndex];
  927.                     if (entry._value != null && entry._value.LockItem == true) {
  928.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_item_locked_cannot_clear));
  929.                     }
  930.                 }
  931.                
  932.                 for (int RemoveIndex = _items.Count - 1; RemoveIndex >= 0; RemoveIndex--) {
  933.                     Entry entry = (Entry)_items[RemoveIndex];
  934.                     if ((CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap && RemoveIndex < _inheritedCount) || (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate && (RemoveIndex >= initialCount - _inheritedCount))) {
  935.                         inheritedRemoved++;
  936.                     }
  937.                     if (entry._entryType == EntryType.Removed) {
  938.                         removedRemoved++;
  939.                     }
  940.                    
  941.                     _items.RemoveAt(RemoveIndex);
  942.                 }
  943.                 _inheritedCount -= inheritedRemoved;
  944.                 _removedItemCount -= removedRemoved;
  945.             }
  946.         }
  947.        
  948.         protected internal void BaseRemoveAt(int index)
  949.         {
  950.             if (IsReadOnly()) {
  951.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
  952.             }
  953.             int VirtualIndex = 0;
  954.             Entry entry = (Entry)null;
  955.            
  956.             foreach (Entry entryfound in _items) {
  957.                 if (VirtualIndex == index && (entryfound._entryType != EntryType.Removed)) {
  958.                     entry = entryfound;
  959.                     break;
  960.                 }
  961.                
  962.                 if (entryfound._entryType != EntryType.Removed) {
  963.                     VirtualIndex++;
  964.                 }
  965.             }
  966.            
  967.             if (entry == null) {
  968.                 throw new ConfigurationErrorsException(SR.GetString(SR.IndexOutOfRange, index));
  969.             }
  970.             else {
  971.                 if (entry._value.LockItem == true) {
  972.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, entry.GetKey(this)));
  973.                 }
  974.                
  975.                 if (entry._value.ElementPresent == false) {
  976.                     CheckLockedElement(_removeElement, null);
  977.                     // has remove been locked?
  978.                 }
  979.                
  980.                 switch (entry._entryType) {
  981.                     case EntryType.Added:
  982.                         if (CollectionType != ConfigurationElementCollectionType.AddRemoveClearMap && CollectionType != ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  983.                             if (CollectionType == ConfigurationElementCollectionType.BasicMapAlternate) {
  984.                                 if (index >= Count - _inheritedCount) {
  985.                                     throw (new ConfigurationErrorsException(SR.GetString(SR.Config_base_cannot_remove_inherited_items)));
  986.                                 }
  987.                             }
  988.                            
  989.                             if (CollectionType == ConfigurationElementCollectionType.BasicMap) {
  990.                                 if (index < _inheritedCount) {
  991.                                     throw (new ConfigurationErrorsException(SR.GetString(SR.Config_base_cannot_remove_inherited_items)));
  992.                                 }
  993.                             }
  994.                            
  995.                             _items.RemoveAt(index);
  996.                            
  997.                         }
  998.                         else {
  999.                             // don't really remove it from the collection just mark it removed
  1000.                             if (entry._value.ElementPresent == false) {
  1001.                                 CheckLockedElement(_removeElement, null);
  1002.                                 // has remove been locked?
  1003.                             }
  1004.                            
  1005.                             entry._entryType = EntryType.Removed;
  1006.                             _removedItemCount++;
  1007.                         }
  1008.                        
  1009.                         break;
  1010.                     case EntryType.Removed:
  1011.                        
  1012.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_entry_already_removed));
  1013.                         break;
  1014.                     default:
  1015.                        
  1016.                         if (CollectionType != ConfigurationElementCollectionType.AddRemoveClearMap && CollectionType != ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  1017.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_collection_elements_may_not_be_removed));
  1018.                         }
  1019.                        
  1020.                         entry._entryType = EntryType.Removed;
  1021.                         _removedItemCount++;
  1022.                         break;
  1023.                 }
  1024.                 bModified = true;
  1025.             }
  1026.         }
  1027.        
  1028.        
  1029.        
  1030.         protected internal override bool SerializeElement(XmlWriter writer, bool serializeCollectionKey)
  1031.         {
  1032.             ConfigurationElementCollectionType type = CollectionType;
  1033.             bool DataToWrite = false;
  1034.            
  1035.             DataToWrite |= base.SerializeElement(writer, serializeCollectionKey);
  1036.            
  1037.             if (type == ConfigurationElementCollectionType.AddRemoveClearMap || type == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  1038.                 // it is possible that the collection only has to be cleared and contains
  1039.                 // no real elements
  1040.                 if (bEmitClearTag == true && (_clearElement.Length != 0)) {
  1041.                     if (writer != null) {
  1042.                         writer.WriteStartElement(_clearElement);
  1043.                         writer.WriteEndElement();
  1044.                     }
  1045.                     DataToWrite = true;
  1046.                 }
  1047.             }
  1048.            
  1049.             foreach (Entry entry in _items) {
  1050.                 if (type == ConfigurationElementCollectionType.BasicMap || type == ConfigurationElementCollectionType.BasicMapAlternate) {
  1051.                     if (entry._entryType == EntryType.Added || entry._entryType == EntryType.Replaced) {
  1052.                         if (ElementName != null && ElementName.Length != 0) {
  1053.                             if (BaseConfigurationRecord.IsReservedAttributeName(ElementName)) {
  1054.                                 throw new ArgumentException(SR.GetString(SR.Basicmap_item_name_reserved, ElementName));
  1055.                             }
  1056.                             DataToWrite |= entry._value.SerializeToXmlElement(writer, ElementName);
  1057.                         }
  1058.                         else {
  1059.                             DataToWrite |= entry._value.SerializeElement(writer, false);
  1060.                         }
  1061.                     }
  1062.                 }
  1063.                 else if (type == ConfigurationElementCollectionType.AddRemoveClearMap || type == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  1064.                     if ((entry._entryType == EntryType.Removed || entry._entryType == EntryType.Replaced) && entry._value != null) {
  1065.                        
  1066.                         if (writer != null) {
  1067.                             writer.WriteStartElement(_removeElement);
  1068.                         }
  1069.                        
  1070.                         DataToWrite |= entry._value.SerializeElement(writer, true);
  1071.                        
  1072.                         if (writer != null) {
  1073.                             writer.WriteEndElement();
  1074.                         }
  1075.                        
  1076.                         DataToWrite = true;
  1077.                     }
  1078.                     if (entry._entryType == EntryType.Added || entry._entryType == EntryType.Replaced) {
  1079.                         DataToWrite |= entry._value.SerializeToXmlElement(writer, _addElement);
  1080.                     }
  1081.                 }
  1082.             }
  1083.             return DataToWrite;
  1084.         }
  1085.        
  1086.         protected override bool OnDeserializeUnrecognizedElement(string elementName, XmlReader reader)
  1087.         {
  1088.             bool handled = false;
  1089.             //
  1090.             if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap || CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  1091.                 if (elementName == _addElement) {
  1092.                     ConfigurationElement elem = CallCreateNewElement();
  1093.                     elem.ResetLockLists(this);
  1094.                     elem.DeserializeElement(reader, false);
  1095.                     BaseAdd(elem);
  1096.                     handled = true;
  1097.                 }
  1098.                 else if (elementName == _removeElement) {
  1099.                     ConfigurationElement elem = CallCreateNewElement();
  1100.                     elem.ResetLockLists(this);
  1101.                     elem.DeserializeElement(reader, true);
  1102.                     if (IsElementRemovable(elem) == true) {
  1103.                         BaseRemove(GetElementKeyInternal(elem), false);
  1104.                     }
  1105.                    
  1106.                     handled = true;
  1107.                 }
  1108.                 else if (elementName == _clearElement) {
  1109.                     if (reader.AttributeCount > 0) {
  1110.                         while (reader.MoveToNextAttribute()) {
  1111.                             string propertyName = reader.Name;
  1112.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_unrecognized_attribute, propertyName), reader);
  1113.                         }
  1114.                     }
  1115.                     CheckLockedElement(elementName, reader);
  1116.                     reader.MoveToElement();
  1117.                     BaseClear();
  1118.                     //
  1119.                     bEmitClearTag = true;
  1120.                     handled = true;
  1121.                 }
  1122.             }
  1123.             else if (elementName == ElementName) {
  1124.                 if (BaseConfigurationRecord.IsReservedAttributeName(elementName)) {
  1125.                     throw new ArgumentException(SR.GetString(SR.Basicmap_item_name_reserved, elementName));
  1126.                 }
  1127.                 ConfigurationElement elem = CallCreateNewElement();
  1128.                 elem.ResetLockLists(this);
  1129.                 elem.DeserializeElement(reader, false);
  1130.                 BaseAdd(elem);
  1131.                
  1132.                 handled = true;
  1133.             }
  1134.             else if (IsElementName(elementName)) {
  1135.                 // this section handle the collection like the allow deny senario which
  1136.                 if (BaseConfigurationRecord.IsReservedAttributeName(elementName)) {
  1137.                     throw new ArgumentException(SR.GetString(SR.Basicmap_item_name_reserved, elementName));
  1138.                 }
  1139.                 // have multiple tags for the collection
  1140.                 ConfigurationElement elem = CallCreateNewElement(elementName);
  1141.                 elem.ResetLockLists(this);
  1142.                 elem.DeserializeElement(reader, false);
  1143.                 BaseAdd(-1, elem);
  1144.                 handled = true;
  1145.             }
  1146.             return handled;
  1147.         }
  1148.        
  1149.         private ConfigurationElement CallCreateNewElement(string elementName)
  1150.         {
  1151.             ConfigurationElement elem = CreateNewElement(elementName);
  1152.             elem.AssociateContext(_configRecord);
  1153.             elem.CallInit();
  1154.             return elem;
  1155.         }
  1156.        
  1157.         private ConfigurationElement CallCreateNewElement()
  1158.         {
  1159.             ConfigurationElement elem = CreateNewElement();
  1160.             elem.AssociateContext(_configRecord);
  1161.             elem.CallInit();
  1162.             return elem;
  1163.         }
  1164.        
  1165.         protected virtual ConfigurationElement CreateNewElement(string elementName)
  1166.         {
  1167.             return CreateNewElement();
  1168.         }
  1169.         protected abstract ConfigurationElement CreateNewElement();
  1170.         protected abstract object GetElementKey(ConfigurationElement element);
  1171.         internal object GetElementKeyInternal(ConfigurationElement element)
  1172.         {
  1173.             object key = GetElementKey(element);
  1174.             if (key == null)
  1175.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_invalid_element_key));
  1176.             return key;
  1177.         }
  1178.        
  1179.         protected virtual bool IsElementRemovable(ConfigurationElement element)
  1180.         {
  1181.             return true;
  1182.         }
  1183.        
  1184.         private bool CompareKeys(object key1, object key2)
  1185.         {
  1186.             if (_comparer != null) {
  1187.                 return (_comparer.Compare(key1, key2) == 0);
  1188.             }
  1189.             else {
  1190.                 return key1.Equals(key2);
  1191.             }
  1192.         }
  1193.        
  1194.         protected virtual string ElementName {
  1195.             get { return ""; }
  1196.         }
  1197.        
  1198.         protected virtual bool IsElementName(string elementName)
  1199.         {
  1200.             return false;
  1201.         }
  1202.        
  1203.         internal bool IsLockableElement(string elementName)
  1204.         {
  1205.             if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap || CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  1206.                 return (elementName == AddElementName || elementName == RemoveElementName || elementName == ClearElementName);
  1207.             }
  1208.             else {
  1209.                 return (elementName == ElementName) || IsElementName(elementName);
  1210.             }
  1211.         }
  1212.        
  1213.         internal string LockableElements {
  1214.             get {
  1215.                 if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap || CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  1216.                    
  1217.                     string ElementNames = "'" + AddElementName + "'";
  1218.                     // Must have an add
  1219.                     if (RemoveElementName.Length != 0)
  1220.                         ElementNames += ", '" + RemoveElementName + "'";
  1221.                     if (ClearElementName.Length != 0)
  1222.                         ElementNames += ", '" + ClearElementName + "'";
  1223.                     return ElementNames;
  1224.                 }
  1225.                 else {
  1226.                     if (!String.IsNullOrEmpty(ElementName)) {
  1227.                         return "'" + ElementName + "'";
  1228.                     }
  1229.                     return String.Empty;
  1230.                 }
  1231.             }
  1232.         }
  1233.        
  1234.         protected virtual bool ThrowOnDuplicate {
  1235.             get {
  1236.                 if (CollectionType == ConfigurationElementCollectionType.AddRemoveClearMap || CollectionType == ConfigurationElementCollectionType.AddRemoveClearMapAlternate) {
  1237.                     return true;
  1238.                 }
  1239.                 return false;
  1240.             }
  1241.         }
  1242.        
  1243.         public virtual ConfigurationElementCollectionType CollectionType {
  1244.             get { return ConfigurationElementCollectionType.AddRemoveClearMap; }
  1245.         }
  1246.        
  1247.         private enum EntryType
  1248.         {
  1249.             Inherited,
  1250.             Replaced,
  1251.             Removed,
  1252.             Added
  1253.         }
  1254.        
  1255.         private class Entry
  1256.         {
  1257.            
  1258.             internal EntryType _entryType;
  1259.             internal object _key;
  1260.             internal ConfigurationElement _value;
  1261.            
  1262.             internal object GetKey(ConfigurationElementCollection ThisCollection)
  1263.             {
  1264.                 // For items that have been really inserted...
  1265.                 if (_value != null) {
  1266.                     return ThisCollection.GetElementKeyInternal(_value);
  1267.                 }
  1268.                 else {
  1269.                     return _key;
  1270.                     // These are items that only have been removed
  1271.                 }
  1272.                
  1273.             }
  1274.            
  1275.             internal Entry(EntryType type, object key, ConfigurationElement value)
  1276.             {
  1277.                 _entryType = type;
  1278.                 _key = key;
  1279.                 _value = value;
  1280.             }
  1281.         }
  1282.        
  1283.         private class Enumerator : IDictionaryEnumerator
  1284.         {
  1285.            
  1286.             private IEnumerator _itemsEnumerator;
  1287.             private DictionaryEntry _current = new DictionaryEntry();
  1288.             private ConfigurationElementCollection ThisCollection;
  1289.            
  1290.            
  1291.             internal Enumerator(ArrayList items, ConfigurationElementCollection collection)
  1292.             {
  1293.                 _itemsEnumerator = items.GetEnumerator();
  1294.                 ThisCollection = collection;
  1295.             }
  1296.            
  1297.             bool IEnumerator.MoveNext()
  1298.             {
  1299.                 while (_itemsEnumerator.MoveNext()) {
  1300.                     Entry entry = (Entry)_itemsEnumerator.Current;
  1301.                     if (entry._entryType != EntryType.Removed) {
  1302.                         _current.Key = (entry.GetKey(ThisCollection) != null) ? entry.GetKey(ThisCollection) : "key";
  1303.                         _current.Value = entry._value;
  1304.                         return true;
  1305.                     }
  1306.                 }
  1307.                 return false;
  1308.             }
  1309.            
  1310.             void IEnumerator.Reset()
  1311.             {
  1312.                 _itemsEnumerator.Reset();
  1313.             }
  1314.            
  1315.             object IEnumerator.Current {
  1316.                 get { return _current.Value; }
  1317.             }
  1318.            
  1319.             DictionaryEntry IDictionaryEnumerator.Entry {
  1320.                 get { return _current; }
  1321.             }
  1322.            
  1323.             object IDictionaryEnumerator.Key {
  1324.                 get { return _current.Key; }
  1325.             }
  1326.            
  1327.             object IDictionaryEnumerator.Value {
  1328.                 get { return _current.Value; }
  1329.             }
  1330.         }
  1331.     }
  1332. }

Developer Fusion