#region Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved //----------------------------------------------------------------------------- // Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved // Web: https://www.technosoftware.com // // The source code in this file is covered under a dual-license scenario: // - Owner of a purchased license: SCLA 1.0 // - GPL V3: everybody else // // SCLA license terms accompanied with this source code. // See SCLA 1.0: https://technosoftware.com/license/Source_Code_License_Agreement.pdf // // GNU General Public License as published by the Free Software Foundation; // version 3 of the License are accompanied with this source code. // See https://technosoftware.com/license/GPLv3License.txt // // This source code is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. //----------------------------------------------------------------------------- #endregion Copyright (c) 2011-2023 Technosoftware GmbH. All rights reserved #region Using Directives using System; using System.Collections; using System.Runtime.Serialization; #endregion namespace Technosoftware.DaAeHdaClient { /// /// A writeable collection class which can be used to expose arrays as properties of classes. /// [Serializable] public class OpcWriteableCollection : ICollection, IList, ICloneable, ISerializable { #region Fields private ArrayList _array; private Type _elementType; #endregion #region Public Interface /// /// An indexer for the collection. /// public virtual object this[int index] { get => _array[index]; set => _array[index] = value; } /// /// Returns a copy of the collection as an array. /// public virtual Array ToArray() { return _array.ToArray(_elementType); } /// /// Adds a list of values to the collection. /// public virtual void AddRange(ICollection collection) { if (collection != null) { foreach (var element in collection) { ValidateElement(element); } _array.AddRange(collection); } } #endregion #region Protected Interface /// /// Creates a collection that wraps the specified array instance. /// protected OpcWriteableCollection(ICollection array, Type elementType) { // copy array. if (array != null) { _array = new ArrayList(array); } else { _array = new ArrayList(); } // set default element type. _elementType = typeof(object); // verify that current contents of the array are the correct type. if (elementType != null) { foreach (var element in _array) { ValidateElement(element); } _elementType = elementType; } } /// /// The array instance exposed by the collection. /// protected virtual ArrayList Array { get => _array; set { _array = value; if (_array == null) { _array = new ArrayList(); } } } /// /// The type of objects allowed in the collection. /// protected virtual Type ElementType { get => _elementType; set { // verify that current contents of the array are the correct type. foreach (var element in _array) { ValidateElement(element); } _elementType = value; } } /// /// Throws an exception if the element is not valid for the collection. /// protected virtual void ValidateElement(object element) { if (element == null) { throw new ArgumentException(string.Format(INVALID_VALUE, element)); } if (!_elementType.IsInstanceOfType(element)) { throw new ArgumentException(string.Format(INVALID_TYPE, element.GetType())); } } /// protected const string INVALID_VALUE = "The value '{0}' cannot be added to the collection."; /// protected const string INVALID_TYPE = "A value with type '{0}' cannot be added to the collection."; #endregion #region ISerializable Members /// /// A set of names for fields used in serialization. /// private class Names { internal const string COUNT = "CT"; internal const string ELEMENT = "EL"; internal const string ELEMENT_TYPE = "ET"; } /// /// Contructs a server by de-serializing its OpcUrl from the stream. /// protected OpcWriteableCollection(SerializationInfo info, StreamingContext context) { _elementType = (Type)info.GetValue(Names.ELEMENT_TYPE, typeof(Type)); var count = (int)info.GetValue(Names.COUNT, typeof(int)); _array = new ArrayList(count); for (var ii = 0; ii < count; ii++) { _array.Add(info.GetValue(Names.ELEMENT + ii.ToString(), typeof(object))); } } /// /// Serializes a server into a stream. /// public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue(Names.ELEMENT_TYPE, _elementType); info.AddValue(Names.COUNT, _array.Count); for (var ii = 0; ii < _array.Count; ii++) { info.AddValue(Names.ELEMENT + ii.ToString(), _array[ii]); } } #endregion #region ICollection Members /// /// Indicates whether access to the ICollection is synchronized (thread-safe). /// public virtual bool IsSynchronized => false; /// /// Gets the number of objects in the collection. /// public virtual int Count => _array.Count; /// /// Copies the objects to an Array, starting at a the specified index. /// /// The one-dimensional Array that is the destination for the objects. /// The zero-based index in the Array at which copying begins. public virtual void CopyTo(Array array, int index) { if (_array != null) { _array.CopyTo(array, index); } } /// /// Indicates whether access to the ICollection is synchronized (thread-safe). /// public virtual object SyncRoot => this; #endregion #region IEnumerable Members /// /// Returns an enumerator that can iterate through a collection. /// /// An IEnumerator that can be used to iterate through the collection. public IEnumerator GetEnumerator() { return _array.GetEnumerator(); } #endregion #region IList Members /// /// Gets a value indicating whether the collection is read-only. /// public virtual bool IsReadOnly => false; /// /// Gets or sets the element at the specified index. /// object IList.this[int index] { get => this[index]; set => this[index] = value; } /// /// Removes the IList item at the specified index. /// /// The zero-based index of the item to remove. public virtual void RemoveAt(int index) { _array.RemoveAt(index); } /// /// Inserts an item to the IList at the specified position. /// /// The zero-based index at which value should be inserted. /// The Object to insert into the IList. public virtual void Insert(int index, object value) { ValidateElement(value); _array.Insert(index, value); } /// /// Removes the first occurrence of a specific object from the IList. /// /// The Object to remove from the IList. public virtual void Remove(object value) { _array.Remove(value); } /// /// Determines whether the IList contains a specific value. /// /// The Object to locate in the IList. /// true if the Object is found in the IList; otherwise, false. public virtual bool Contains(object value) { return _array.Contains(value); } /// /// Removes all items from the IList. /// public virtual void Clear() { _array.Clear(); } /// /// Determines the index of a specific item in the IList. /// /// The Object to locate in the IList. /// The index of value if found in the list; otherwise, -1. public virtual int IndexOf(object value) { return _array.IndexOf(value); } /// /// Adds an item to the IList. /// /// The Object to add to the IList. /// The position into which the new element was inserted. public virtual int Add(object value) { ValidateElement(value); return _array.Add(value); } /// /// Indicates whether the IList has a fixed size. /// public virtual bool IsFixedSize => false; #endregion #region ICloneable Members /// /// Creates a deep copy of the collection. /// public virtual object Clone() { var clone = (OpcWriteableCollection)MemberwiseClone(); clone._array = new ArrayList(); for (var ii = 0; ii < _array.Count; ii++) { clone.Add(OpcConvert.Clone(_array[ii])); } return clone; } #endregion } }