339 lines · 14.7 KB · C#
RawDownload
//******************************************************************************************************//  ChannelCollectionBase.cs - Gbtc////  Copyright © 2012, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may//  not use this file except in compliance with the License. You may obtain a copy of the License at:////      http://www.opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  3/7/2005 - J. Ritchie Carroll//       Generated original version of source code.//  09/15/2009 - Stephen C. Wills//       Added new header and license agreement.//  12/17/2012 - Starlynn Danyelle Gilliam//       Modified Header.////****************************************************************************************************** using System;using System.Collections.Generic;using System.Collections.Specialized;using System.Linq;using System.Runtime.Serialization;using GSF.Collections;using GSF.Parsing; // ReSharper disable VirtualMemberCallInConstructornamespace GSF.PhasorProtocols{    /// <summary>    /// Represents a protocol independent collection of <see cref="IChannel"/> objects.<br/>    /// This is the base class of all collection classes in the phasor protocols library;    /// it is the root of the collection class hierarchy.    /// </summary>    /// <remarks>    /// This channel collection implements <see cref="IChannel"/> (inherited via <see cref="IChannelCollection{T}"/>) for the benefit    /// of providing a cumulative binary image of the entire collection.    /// </remarks>    /// <typeparam name="T">Specific <see cref="IChannel"/> type that the <see cref="ChannelCollectionBase{T}"/> contains.</typeparam>    [Serializable]    public abstract class ChannelCollectionBase<T> : ListCollection<T>, IChannelCollection<T> where T : IChannel    {        #region [ Members ]         // Events         /// <summary>        /// Notifies listeners of dynamic changes, such as when items get added and removed or the whole list is refreshed.        /// </summary>        public event NotifyCollectionChangedEventHandler CollectionChanged;         // Fields        private int m_lastValidIndex;                       // Last valid index in the collection (i.e., maximum value count - 1)        private IChannelParsingState m_state;               // Current parsing state        private Dictionary<string, string> m_attributes;    // Attributes dictionary        private object m_tag;                               // User defined tag         #endregion         #region [ Constructors ]         /// <summary>        /// Creates a new <see cref="ChannelCollectionBase{T}"/>.        /// </summary>        protected ChannelCollectionBase()        {            m_lastValidIndex = int.MaxValue;        }         /// <summary>        /// Creates a new <see cref="ChannelCollectionBase{T}"/> using specified <paramref name="lastValidIndex"/>.        /// </summary>        /// <param name="lastValidIndex">Last valid index for the collection (i.e., maximum count - 1).</param>        /// <param name="fixedElementSize">Flag that indicates if collections elements have a fixed size.</param>        /// <remarks>        /// <paramref name="lastValidIndex"/> is used instead of maximum count so that maximum type values may        /// be specified as needed. For example, if the protocol specifies a collection with a signed 16-bit        /// maximum length you can specify <see cref="short.MaxValue"/> (i.e., 32,767) as the last valid index        /// for the collection since total number of items supported would be 32,768.        /// </remarks>        protected ChannelCollectionBase(int lastValidIndex, bool fixedElementSize)        {            m_lastValidIndex = lastValidIndex;            FixedElementSize = fixedElementSize;        }         /// <summary>        /// Creates a new <see cref="ChannelCollectionBase{T}"/> from serialization parameters.        /// </summary>        /// <param name="info">The <see cref="SerializationInfo"/> with populated with data.</param>        /// <param name="context">The source <see cref="StreamingContext"/> for this deserialization.</param>        protected ChannelCollectionBase(SerializationInfo info, StreamingContext context)        {            // Deserialize collection            m_lastValidIndex = info.GetInt32("maximumCount") - 1;            FixedElementSize = info.GetOrDefault("fixedElementSize", true);             for (int x = 0; x < info.GetInt32("count"); x++)                Add((T)info.GetValue($"item{x}", typeof(T)));        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets or sets the maximum allowed number of items for this <see cref="ChannelCollectionBase{T}"/>.        /// </summary>        public virtual int MaximumCount        {            get => m_lastValidIndex + 1;            set => m_lastValidIndex = value - 1;        }         /// <summary>        /// Gets or sets the parsing state for this <see cref="IChannel"/> object.        /// </summary>        public virtual IChannelParsingState State        {            get => m_state;            set => m_state = value;        }         /// <summary>        /// Gets the length of the <see cref="ChannelCollectionBase{T}"/>.        /// </summary>        /// <remarks>        /// The length of the <see cref="ChannelCollectionBase{T}"/> binary image is the combined length of all the items in the collection.<br/>        /// The default implementation assumes all <see cref="IChannel"/> items in the collection have the same length, hence the value returned        /// is the <see cref="ISupportBinaryImage.BinaryLength"/> of the first item in the collection times the <see cref="List{T}.Count"/>.        /// </remarks>        public virtual int BinaryLength        {            get            {                if (FixedElementSize)                {                    int count = Count;                    return count > 0 ? this[0].BinaryLength * count : 0;                }                                return this.Sum(item => item.BinaryLength);            }        }         /// <summary>        /// Gets flag that indicates if collection elements have a fixed size.        /// </summary>        public virtual bool FixedElementSize { get; }         /// <summary>        /// Gets a <see cref="Dictionary{TKey,TValue}"/> of string based property names and values for this <see cref="IChannel"/> object.        /// </summary>        public virtual Dictionary<string, string> Attributes        {            get            {                // Create a new attributes dictionary or clear the contents of any existing one                if (m_attributes is null)                    m_attributes = new Dictionary<string, string>();                else                    m_attributes.Clear();                 m_attributes.Add("Derived Type", GetType().Name);                m_attributes.Add("Binary Length", BinaryLength.ToString());                m_attributes.Add("Maximum Count", MaximumCount.ToString());                m_attributes.Add("Current Count", Count.ToString());                m_attributes.Add("Fixed Element Size", FixedElementSize.ToString());                 return m_attributes;            }        }         /// <summary>        /// Gets or sets a user definable reference to an object associated with this <see cref="IChannel"/> object.        /// </summary>        public virtual object Tag        {            get => m_tag;            set => m_tag = value;        }         #endregion         #region [ Methods ]         /// <summary>        /// Generates binary image of the object and copies it into the given buffer, for <see cref="ISupportBinaryImage.BinaryLength"/> bytes.        /// </summary>        /// <param name="buffer">Buffer used to hold generated binary image of the source object.</param>        /// <param name="startIndex">0-based starting index in the <paramref name="buffer"/> to start writing.</param>        /// <returns>The number of bytes written to the <paramref name="buffer"/>.</returns>        /// <exception cref="ArgumentNullException"><paramref name="buffer"/> is null.</exception>        /// <exception cref="ArgumentOutOfRangeException">        /// <paramref name="startIndex"/> or <see cref="BinaryLength"/> is less than 0 -or-         /// <paramref name="startIndex"/> and <see cref="BinaryLength"/> will exceed <paramref name="buffer"/> length.        /// </exception>        public virtual int GenerateBinaryImage(byte[] buffer, int startIndex)        {            buffer.ValidateParameters(startIndex, BinaryLength);             int index = startIndex;             // Copy in each element's binary image            for (int x = 0; x < Count; x++)                this[x].CopyImage(buffer, ref index);             return index - startIndex;        }         // Collections are not designed to parse binary images        int ISupportBinaryImage.ParseBinaryImage(byte[] buffer, int startIndex, int length) =>             throw new NotImplementedException();         /// <summary>        /// Adds the elements of the specified collection to the end of the <see cref="ChannelCollectionBase{T}"/>.        /// </summary>        /// <param name="collection">        /// The collection whose elements should be added to the end of the <see cref="ChannelCollectionBase{T}"/>.        /// The collection itself cannot be null, but it can contain elements that are null, if type T is a reference type.        /// </param>        /// <exception cref="ArgumentNullException"><paramref name="collection"/> is null.</exception>        public virtual void AddRange(IEnumerable<T> collection)        {            if (collection is null)                throw new ArgumentNullException(nameof(collection), "collection is null");             foreach (T item in collection)                Add(item);        }         /// <summary>        /// Manually sends a <see cref="NotifyCollectionChangedAction.Reset"/> to the collection changed event.        /// </summary>        public virtual void RefreshBinding() =>             CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));         /// <summary>        /// Inserts an element into the <see cref="ChannelCollectionBase{T}"/> at the specified index.        /// </summary>        /// <param name="index">The zero-based index at which item should be inserted.</param>        /// <param name="item">The object to insert.</param>        /// <exception cref="OverflowException">Maximum collection item limit reached.</exception>        protected override void InsertItem(int index, T item)        {            // Interception of inserted items occurs with this override (via Collection<T>) allowing maximum length to be validated            if (Count > m_lastValidIndex)                throw new OverflowException($"Maximum {GetType().Name} item limit reached");             base.InsertItem(index, item);             CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));        }         /// <summary>        /// Removes the element at the specified index of the <see cref="ChannelCollectionBase{T}"/>.        /// </summary>        /// <param name="index">The zero-based index of the element to remove.</param>        protected override void RemoveItem(int index)        {            if (CollectionChanged is null)            {                base.RemoveItem(index);            }            else            {                T oldItem = Items[index];                base.RemoveItem(index);                 // ReSharper disable once PossibleNullReferenceException                CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItem, index));            }        }         /// <summary>        /// Replaces the element at the specified index.        /// </summary>        /// <param name="index">The zero-based index of the element to replace.</param>        /// <param name="item">The new value for the element at the specified index. The value can be null for reference types.</param>        protected override void SetItem(int index, T item)        {            if (CollectionChanged == null)            {                base.SetItem(index, item);            }            else            {                T oldItem = Items[index];                base.SetItem(index, item);                 // ReSharper disable once PossibleNullReferenceException                CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, oldItem, index));            }        }         /// <summary>        /// Removes all elements from the <see cref="ChannelCollectionBase{T}"/>.        /// </summary>        protected override void ClearItems()        {            base.ClearItems();            CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));        }         /// <summary>        /// Raises the <see cref="NotifyCollectionChangedEventHandler"/> event.        /// </summary>        /// <param name="e">Changed event arguments.</param>        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) =>            CollectionChanged?.Invoke(this, e);         /// <summary>        /// Populates a <see cref="SerializationInfo"/> with the data needed to serialize the target object.        /// </summary>        /// <param name="info">The <see cref="SerializationInfo"/> to populate with data.</param>        /// <param name="context">The destination <see cref="StreamingContext"/> for this serialization.</param>        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)        {            // Serialize collection            info.AddValue("maximumCount", m_lastValidIndex + 1);            info.AddValue("fixedElementSize", FixedElementSize);            info.AddValue("count", Count);             for (int x = 0; x < Count; x++)                info.AddValue($"item{x}", this[x], typeof(T));        }         #endregion    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t