StateManagedCollection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / Web / UI / StateManagedCollection.cs / 1305376 / StateManagedCollection.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.UI { 
 
    using System;
    using System.Collections; 
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Drawing.Design; 
    using System.Reflection;
    using System.Web.UI; 
    using System.Web.UI.WebControls; 
    using System.Web.Util;
 
    /// 
    /// Manages state for an arbitrary collection of items that implement IStateManager.
    /// The collection differentiates between known types and unknown types.
    /// Known types take up less space in ViewState because only an index needs to be stored instead of a fully qualified type name. 
    /// Unknown types need to have their fully qualified type name stored in ViewState so they take up more space.
    ///  
    public abstract class StateManagedCollection : IList, IStateManager { 

        private ArrayList _collectionItems; 

        private bool _tracking;
        private bool _saveAll;
 
        // We want to know if the collection had items to begin with
        // so we don't put empty collections in the ViewState unnecessarily 
        private bool _hadItems; 

 

        /// 
        /// Creates a new instance of StateManagedCollection.
        ///  
        protected StateManagedCollection() {
            _collectionItems = new ArrayList(); 
        } 

 

        /// 
        /// Returns the number of items in the collection.
        ///  
        public int Count {
            get { 
                return _collectionItems.Count; 
            }
        } 


        /// 
        /// Removes all the items from the collection. 
        /// 
        public void Clear() { 
            OnClear(); 
            _collectionItems.Clear();
            OnClearComplete(); 

            if (_tracking) {
                _saveAll = true;
            } 
        }
 
 
        public void CopyTo(Array array, int index) {
            _collectionItems.CopyTo(array, index); 
        }


        ///  
        /// Creates an object of a known type based on an index into an array of types.
        /// Indexes passed into CreateKnownType() must mach the indexes of the ArrayList returned 
        /// by GetKnownTypes(). 
        /// 
        protected virtual object CreateKnownType(int index) { 
            throw new InvalidOperationException(SR.GetString(SR.StateManagedCollection_NoKnownTypes));
        }

 
        /// 
        /// Returns the IEnumerator for the collection. 
        ///  
        public IEnumerator GetEnumerator() {
            return _collectionItems.GetEnumerator(); 
        }


        ///  
        /// Returns an ordered list of known types.
        ///  
        protected virtual Type[] GetKnownTypes() { 
            return null;
        } 

        /// 
        /// Returns the number of known types.
        ///  
        private int GetKnownTypeCount() {
            Type[] types = GetKnownTypes(); 
 
            if (types == null)
                return 0; 

            return types.Length;
        }
 
        /// 
        /// Inserts a new object into the collection at a given index. 
        /// If the index is -1 then the object is appended to the end of the collection. 
        /// 
        private void InsertInternal(int index, object o) { 
            Debug.Assert(index >= -1 && index <= Count, "Expected index to be at least -1 and less than or equal to Count.");
            if (o == null) {
                throw new ArgumentNullException("o");
            } 

            if (((IStateManager)this).IsTrackingViewState) { 
                ((IStateManager)o).TrackViewState(); 
                SetDirtyObject(o);
            } 

            OnInsert(index, o);

            int trueIndex; 

            if (index == -1) { 
                trueIndex = _collectionItems.Add(o); 
            }
            else { 
                trueIndex = index;
                _collectionItems.Insert(index, o);
            }
 
            try {
                OnInsertComplete(index, o); 
            } 
            catch {
                _collectionItems.RemoveAt(trueIndex); 
                throw;
            }
        }
 
        /// 
        /// Loads all items from view state. 
        ///  
        private void LoadAllItemsFromViewState(object savedState) {
            Debug.Assert(savedState != null); 
            Debug.Assert(savedState is Pair);

            Pair p1 = (Pair)savedState;
 
            if (p1.Second is Pair) {
                Pair p2 = (Pair)p1.Second; 
 
                // save all mode; some objects are typed
                object[] states = (object[])p1.First; 
                int[] typeIndices = (int[])p2.First;
                ArrayList typedObjectTypeNames = (ArrayList)p2.Second;

                Clear(); 

                for (int i = 0; i < states.Length; i++) { 
                    object o; 

                    // If there is only one known type, we don't need type indices 
                    if (typeIndices == null) {
                        // Create known type
                        o = CreateKnownType(0);
                    } 
                    else {
                        int typeIndex = typeIndices[i]; 
 
                        if (typeIndex < GetKnownTypeCount()) {
                            // Create known type 
                            o = CreateKnownType(typeIndex);
                        }
                        else {
                            string typeName = (string)typedObjectTypeNames[typeIndex - GetKnownTypeCount()]; 
                            Type type = Type.GetType(typeName);
 
                            o = Activator.CreateInstance(type); 
                        }
                    } 

                    ((IStateManager)o).TrackViewState();
                    ((IStateManager)o).LoadViewState(states[i]);
 
                    ((IList)this).Add(o);
                } 
            } 
            else {
                Debug.Assert(p1.First is object[]); 

                // save all mode; all objects are instances of known types
                object[] states = (object[])p1.First;
                int[] typeIndices = (int[])p1.Second; 

                Clear(); 
 
                for (int i = 0; i < states.Length; i++) {
                    // Create known type 
                    int typeIndex = 0;
                    if (typeIndices != null) {
                        typeIndex = (int)typeIndices[i];
                    } 
                    object o = CreateKnownType(typeIndex);
 
                    ((IStateManager)o).TrackViewState(); 
                    ((IStateManager)o).LoadViewState(states[i]);
 
                    ((IList)this).Add(o);
                }
            }
        } 

        ///  
        /// Loads only changed items from view state. 
        /// 
        private void LoadChangedItemsFromViewState(object savedState) { 
            Debug.Assert(savedState != null);
            Debug.Assert(savedState is Triplet);

            Triplet t = (Triplet)savedState; 

            if (t.Third is Pair) { 
                // save some mode; some new objects are typed 
                Pair p = (Pair)t.Third;
 
                ArrayList indices = (ArrayList)t.First;
                ArrayList states = (ArrayList)t.Second;
                ArrayList typeIndices = (ArrayList)p.First;
                ArrayList typedObjectTypeNames = (ArrayList)p.Second; 

                for (int i = 0; i < indices.Count; i++) { 
                    int index = (int)indices[i]; 

                    if (index < Count) { 
                        ((IStateManager)((IList)this)[index]).LoadViewState(states[i]);
                    }
                    else {
                        object o; 

                        // If there is only one known type, we don't need type indices 
                        if (typeIndices == null) { 
                            // Create known type
                            o = CreateKnownType(0); 
                        }
                        else {
                            int typeIndex = (int)typeIndices[i];
 
                            if (typeIndex < GetKnownTypeCount()) {
                                // Create known type 
                                o = CreateKnownType(typeIndex); 
                            }
                            else { 
                                string typeName = (string)typedObjectTypeNames[typeIndex - GetKnownTypeCount()];
                                Type type = Type.GetType(typeName);

                                o = Activator.CreateInstance(type); 
                            }
                        } 
 
                        ((IStateManager)o).TrackViewState();
                        ((IStateManager)o).LoadViewState(states[i]); 

                        ((IList)this).Add(o);
                    }
                } 
            }
            else { 
                // save some mode; all new objects are instances of known types 
                ArrayList indices = (ArrayList)t.First;
                ArrayList states = (ArrayList)t.Second; 
                ArrayList typeIndices = (ArrayList)t.Third;

                for (int i = 0; i < indices.Count; i++) {
                    int index = (int)indices[i]; 

                    if (index < Count) { 
                        ((IStateManager)((IList)this)[index]).LoadViewState(states[i]); 
                    }
                    else { 
                        // Create known type
                        int typeIndex = 0;
                        if (typeIndices != null) {
                            typeIndex = (int)typeIndices[i]; 
                        }
                        object o = CreateKnownType(typeIndex); 
 
                        ((IStateManager)o).TrackViewState();
                        ((IStateManager)o).LoadViewState(states[i]); 

                        ((IList)this).Add(o);
                    }
                } 
            }
        } 
 

        ///  
        /// Called when the Clear() method is starting.
        /// 
        protected virtual void OnClear() {
        } 

 
        ///  
        /// Called when the Clear() method is complete.
        ///  
        protected virtual void OnClearComplete() {
        }

 
        /// 
        /// Called when an object must be validated. 
        ///  
        protected virtual void OnValidate(object value) {
            if (value == null) throw new ArgumentNullException("value"); 
        }


        ///  
        /// Called when the Insert() method is starting.
        ///  
        protected virtual void OnInsert(int index, object value) { 
        }
 

        /// 
        /// Called when the Insert() method is complete.
        ///  
        protected virtual void OnInsertComplete(int index, object value) {
        } 
 

        ///  
        /// Called when the Remove() method is starting.
        /// 
        protected virtual void OnRemove(int index, object value) {
        } 

 
        ///  
        /// Called when the Remove() method is complete.
        ///  
        protected virtual void OnRemoveComplete(int index, object value) {
        }

        ///  
        /// Saves all items in the collection to view state.
        ///  
        private object SaveAllItemsToViewState() { 
            Debug.Assert(_saveAll);
 
            bool hasState = false;

            int count = _collectionItems.Count;
 
            int[] typeIndices = new int[count];
            object[] states = new object[count]; 
 
            ArrayList typedObjectTypeNames = null;
            IDictionary typedObjectTracker = null; 

            int knownTypeCount = GetKnownTypeCount();

 
            for (int i = 0; i < count; i++) {
                object o = _collectionItems[i]; 
                SetDirtyObject(o); 

                states[i] = ((IStateManager)o).SaveViewState(); 

                if (states[i] != null)
                    hasState = true;
 
                Type objectType = o.GetType();
 
                int knownTypeIndex = -1; 

                // If there are known types, find index 
                if (knownTypeCount != 0) {
                    knownTypeIndex = ((IList)GetKnownTypes()).IndexOf(objectType);
                }
 
                if (knownTypeIndex != -1) {
                    // Type is known 
                    typeIndices[i] = knownTypeIndex; 
                }
                else { 
                    // Type is unknown
                    if (typedObjectTypeNames == null) {
                        typedObjectTypeNames = new ArrayList();
                        typedObjectTracker = new HybridDictionary(); 
                    }
 
                    // Get index of type 
                    object index = typedObjectTracker[objectType];
 
                    // If type is not in list, add it to the list
                    if (index == null) {
                        typedObjectTypeNames.Add(objectType.AssemblyQualifiedName);
 
                        // Offset the index by the known type count
                        index = typedObjectTypeNames.Count + knownTypeCount - 1; 
                        typedObjectTracker[objectType] = index; 
                    }
 
                    typeIndices[i] = (int)index;
                }
            }
 
            // If the collection didn't have items to begin with don't save the state
            if (!_hadItems && !hasState) { 
                return null; 
            }
 
            if (typedObjectTypeNames == null) {
                // all objects are instances known types

                // If there is only one known type, then all objects are of that type so the indices are not needed 
                if (knownTypeCount == 1)
                    typeIndices = null; 
 
                return new Pair(states, typeIndices);
            } 
            else {
                return new Pair(states, new Pair(typeIndices, typedObjectTypeNames));
            }
        } 

        ///  
        /// Saves changed items to view state. 
        /// 
        private object SaveChangedItemsToViewState() { 
            Debug.Assert(_saveAll == false);

            bool hasState = false;
 
            int count = _collectionItems.Count;
 
            ArrayList indices = new ArrayList(); 
            ArrayList states = new ArrayList();
            ArrayList typeIndices = new ArrayList(); 

            ArrayList typedObjectTypeNames = null;
            IDictionary typedObjectTracker = null;
 
            int knownTypeCount = GetKnownTypeCount();
 
 
            for (int i = 0; i < count; i++) {
                object o = _collectionItems[i]; 

                object state = ((IStateManager)o).SaveViewState();
                if (state != null) {
                    hasState = true; 

                    indices.Add(i); 
                    states.Add(state); 

                    Type objectType = o.GetType(); 

                    int knownTypeIndex = -1;

                    // If there are known types, find index 
                    if (knownTypeCount != 0) {
                        knownTypeIndex = ((IList)GetKnownTypes()).IndexOf(objectType); 
                    } 

                    if (knownTypeIndex != -1) { 
                        // Type is known
                        typeIndices.Add(knownTypeIndex);
                    }
                    else { 
                        // Type is unknown
                        if (typedObjectTypeNames == null) { 
                            typedObjectTypeNames = new ArrayList(); 
                            typedObjectTracker = new HybridDictionary();
                        } 

                        object index = typedObjectTracker[objectType];
                        if (index == null) {
                            typedObjectTypeNames.Add(objectType.AssemblyQualifiedName); 

                            // Offset the index by the known type count 
                            index = typedObjectTypeNames.Count + knownTypeCount - 1; 
                            typedObjectTracker[objectType] = index;
                        } 

                        typeIndices.Add(index);
                    }
                } 
            }
 
            // If the collection didn't have items to begin with don't save the state 
            if (!_hadItems && !hasState) {
                return null; 
            }

            if (typedObjectTypeNames == null) {
                // all objects are instances known types 

                // If there is only one known type, then all objects are of that type so the indices are not needed 
                if (knownTypeCount == 1) 
                    typeIndices = null;
 
                return new Triplet(indices, states, typeIndices);
            }
            else {
                return new Triplet(indices, states, new Pair(typeIndices, typedObjectTypeNames)); 
            }
        } 
 
        /// 
        /// Forces the entire collection to be serialized into viewstate, not just 
        /// the change-information. This is useful when a collection has changed in
        /// a significant way and change information would be insufficient to
        /// recreate the object.
        ///  
        public void SetDirty() {
            _saveAll = true; 
        } 

 
        /// 
        /// Flags an object to record its entire state instead of just changed parts.
        /// 
        protected abstract void SetDirtyObject(object o); 

 
 
        /// 
        IEnumerator IEnumerable.GetEnumerator() { 
            return GetEnumerator();
        }

 

        ///  
        int ICollection.Count { 
            get {
                return Count; 
            }
        }

 
        /// 
        bool ICollection.IsSynchronized { 
            get { 
                return false;
            } 
        }


        ///  
        object ICollection.SyncRoot {
            get { 
                return null; 
            }
        } 


        /// 
        bool IList.IsFixedSize { 
            get {
                return false; 
            } 
        }
 

        /// 
        bool IList.IsReadOnly {
            get { 
                return _collectionItems.IsReadOnly;
            } 
        } 

 
        /// 
        object IList.this[int index] {
            get {
                return _collectionItems[index]; 
            }
            set { 
                if (index < 0 || index >= Count) { 
                    throw new ArgumentOutOfRangeException("index", SR.GetString(SR.StateManagedCollection_InvalidIndex));
                } 
                ((IList)this).RemoveAt(index);
                ((IList)this).Insert(index, value);
            }
        } 

 
        ///  
        int IList.Add(object value) {
            OnValidate(value); 

            InsertInternal(-1, value);

            return _collectionItems.Count - 1; 
        }
 
 
        /// 
        void IList.Clear() { 
            Clear();
        }

 
        /// 
        bool IList.Contains(object value) { 
            if (value == null) { 
                return false;
            } 

            OnValidate(value);

            return _collectionItems.Contains(value); 
        }
 
 
        /// 
        int IList.IndexOf(object value) { 
            if (value == null) {
                return -1;
            }
 
            OnValidate(value);
 
            return _collectionItems.IndexOf(value); 
        }
 

        /// 
        void IList.Insert(int index, object value) {
            if (value == null) { 
                throw new ArgumentNullException("value");
            } 
            if (index < 0 || index > Count) { 
                throw new ArgumentOutOfRangeException("index", SR.GetString(SR.StateManagedCollection_InvalidIndex));
            } 

            OnValidate(value);

            InsertInternal(index, value); 

            if (_tracking) { 
                _saveAll = true; 
            }
        } 


        /// 
        void IList.Remove(object value) { 
            if (value == null) {
                return; 
            } 

            OnValidate(value); 

            ((IList)this).RemoveAt(((IList)this).IndexOf(value));
        }
 

        ///  
        void IList.RemoveAt(int index) { 
            object o = _collectionItems[index];
 
            OnRemove(index, o);
            _collectionItems.RemoveAt(index);
            try {
                OnRemoveComplete(index, o); 
            }
            catch { 
                _collectionItems.Insert(index, o); 
                throw;
            } 

            if (_tracking) {
                _saveAll = true;
            } 
        }
 
 

        ///  
        bool IStateManager.IsTrackingViewState {
            get {
                return _tracking;
            } 
        }
 
 
        /// 
        void IStateManager.LoadViewState(object savedState) { 

            if (savedState != null) {
                if (savedState is Triplet) {
                    LoadChangedItemsFromViewState(savedState); 
                }
                else { 
                    LoadAllItemsFromViewState(savedState); 
                }
            } 
        }


        ///  
        object IStateManager.SaveViewState() {
 
            if (_saveAll) { 
                return SaveAllItemsToViewState();
            } 
            else {
                return SaveChangedItemsToViewState();
            }
        } 

 
        ///  
        void IStateManager.TrackViewState() {
            if (!((IStateManager)this).IsTrackingViewState) { 
                _hadItems = Count > 0;

                _tracking = true;
 
                foreach (IStateManager o in _collectionItems) {
                    o.TrackViewState(); 
                } 
            }
        } 
    }
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK