File: System\Activities\HybridCollection.cs
Project: ndp\cdf\src\NetFx40\System.Activities\System.Activities.csproj (System.Activities)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
 
namespace System.Activities
{
    using System;
    using System.Runtime.Serialization;
    using System.Collections.Generic;
    using System.Runtime;
    using System.Collections.ObjectModel;
 
    // used internally for performance in cases where a common usage pattern is a single item
    [DataContract]
    class HybridCollection<T>
        where T : class
    {
        List<T> multipleItems;
        T singleItem;
 
        public HybridCollection()
        {
        }
 
        public HybridCollection(T initialItem)
        {
            Fx.Assert(initialItem != null, "null is used as a sentinal value and is not a valid item value for a hybrid collection");
            this.singleItem = initialItem;
        }
 
        public T this[int index]
        {
            get
            {
                if (this.singleItem != null)
                {
                    Fx.Assert(index == 0, "Out of range with a single item");
                    return this.singleItem;
                }
                else if (this.multipleItems != null)
                {
                    Fx.Assert(index >= 0 && index < this.multipleItems.Count, "Out of range with multiple items.");
 
                    return this.multipleItems[index];
                }
 
                Fx.Assert("Out of range.  There were no items in the HybridCollection.");
                return default(T);
            }
        }
 
        public int Count
        {
            get
            {
                if (this.singleItem != null)
                {
                    return 1;
                }
 
                if (this.multipleItems != null)
                {
                    return this.multipleItems.Count;
                }
 
                return 0;
            }
        }
 
        protected T SingleItem
        {
            get
            {
                return this.singleItem;
            }
        }
 
        protected IList<T> MultipleItems
        {
            get
            {
                return this.multipleItems;
            }
        }
 
        [DataMember(EmitDefaultValue = false, Name = "multipleItems")]
        internal List<T> SerializedMultipleItems
        {
            get { return this.multipleItems; }
            set { this.multipleItems = value; }
        }
 
        [DataMember(EmitDefaultValue = false, Name = "singleItem")]
        internal T SerializedSingleItem
        {
            get { return this.singleItem; }
            set { this.singleItem = value; }
        }
 
        public void Add(T item)
        {
            Fx.Assert(item != null, "null is used as a sentinal value and is not a valid item value for a hybrid collection");
            if (this.multipleItems != null)
            {
                this.multipleItems.Add(item);
            }
            else if (this.singleItem != null)
            {
                this.multipleItems = new List<T>(2);
                this.multipleItems.Add(this.singleItem);
                this.multipleItems.Add(item);
                this.singleItem = null;
            }
            else
            {
                this.singleItem = item;
            }
        }
 
        public ReadOnlyCollection<T> AsReadOnly()
        {
            if (this.multipleItems != null)
            {
                return new ReadOnlyCollection<T>(this.multipleItems);
            }
            else if (this.singleItem != null)
            {
                return new ReadOnlyCollection<T>(new T[1] { this.singleItem });
            }
            else
            {
                return new ReadOnlyCollection<T>(new T[0]);
            }
        }
 
        // generally used for serialization purposes
        public void Compress()
        {
            if (this.multipleItems != null && this.multipleItems.Count == 1)
            {
                this.singleItem = this.multipleItems[0];
                this.multipleItems = null;
            }
        }
 
        public void Remove(T item)
        {
            Remove(item, false);
        }
 
        internal void Remove(T item, bool searchingFromEnd)
        {
            if (this.singleItem != null)
            {
                Fx.Assert(object.Equals(item, this.singleItem), "The given item should be in this list. Something is wrong in our housekeeping.");
                this.singleItem = null;
            }
            else
            {
                Fx.Assert(this.multipleItems != null && this.multipleItems.Contains(item), "The given item should be in this list. Something is wrong in our housekeeping.");
                int position = (searchingFromEnd) ? this.multipleItems.LastIndexOf(item) : this.multipleItems.IndexOf(item);
                if (position != -1)
                {
                    this.multipleItems.RemoveAt(position);
                }
            }
        }
    }
}