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