MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.Diagnostics.CodeAnalysis; // for fxcop8using System.Reflection;9using System.Runtime.Serialization;10using System.Threading;11 12using Dbg = System.Management.Automation.Diagnostics;13 14namespace System.Management.Automation15{16 #region DataAddedEventArgs17 18 /// <summary>19 /// Event arguments passed to PSDataCollection DataAdded handlers.20 /// </summary>21 public sealed class DataAddedEventArgs : EventArgs22 {23 #region Private Data24 25 #endregion26 27 #region Constructor28 29 /// <summary>30 /// Constructor.31 /// </summary>32 /// <param name="psInstanceId">33 /// PowerShell InstanceId which added this data.34 /// Guid.Empty, if the data is not added by a PowerShell35 /// instance.36 /// </param>37 /// <param name="index">38 /// Index at which the data is added.39 /// </param>40 internal DataAddedEventArgs(Guid psInstanceId, int index)41 {42 PowerShellInstanceId = psInstanceId;43 Index = index;44 }45 46 #endregion47 48 #region Properties49 50 /// <summary>51 /// Index at which the data is added.52 /// </summary>53 public int Index { get; }54 55 /// <summary>56 /// PowerShell InstanceId which added this data.57 /// Guid.Empty, if the data is not added by a PowerShell58 /// instance.59 /// </summary>60 public Guid PowerShellInstanceId { get; }61 62 #endregion63 }64 65 #endregion66 67 /// <summary>68 /// Event arguments passed to PSDataCollection DataAdding handlers.69 /// </summary>70 public sealed class DataAddingEventArgs : EventArgs71 {72 #region Private Data73 74 #endregion75 76 #region Constructor77 78 /// <summary>79 /// Constructor.80 /// </summary>81 /// <param name="psInstanceId">82 /// PowerShell InstanceId which added this data.83 /// Guid.Empty, if the data is not added by a PowerShell84 /// instance.85 /// </param>86 /// <param name="itemAdded">87 /// The actual item about to be added.88 /// </param>89 internal DataAddingEventArgs(Guid psInstanceId, object itemAdded)90 {91 PowerShellInstanceId = psInstanceId;92 ItemAdded = itemAdded;93 }94 95 #endregion96 97 #region Properties98 99 /// <summary>100 /// The item about to be added.101 /// </summary>102 public object ItemAdded { get; }103 104 /// <summary>105 /// PowerShell InstanceId which added this data.106 /// Guid.Empty, if the data is not added by a PowerShell107 /// instance.108 /// </summary>109 public Guid PowerShellInstanceId { get; }110 111 #endregion112 }113 114 #region PSDataCollection115 116 /// <summary>build117 /// Thread Safe buffer used with PowerShell Hosting interfaces.118 /// </summary>119 public class PSDataCollection<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable, IDisposable, ISerializable120 {121 #region Private Data122 123 private readonly IList<T> _data;124 private ManualResetEvent _readWaitHandle;125 private bool _isOpen = true;126 private bool _releaseOnEnumeration;127 private bool _isEnumerated;128 // a counter to keep track of active PowerShell instances129 // using this buffer.130 private int _refCount;131 132 private bool _isDisposed = false;133 134 /// <summary>135 /// Whether the enumerator needs to be blocking136 /// by default.137 /// </summary>138 private bool _blockingEnumerator = false;139 140 /// <summary>141 /// Whether the ref count was incremented when142 /// BlockingEnumerator was updated.143 /// </summary>144 private bool _refCountIncrementedForBlockingEnumerator = false;145 146 private int _countNewData = 0;147 private int _dataAddedFrequency = 1;148 private Guid _sourceGuid = Guid.Empty;149 150 #endregion151 152 #region Public Constructors153 154 /// <summary>155 /// Default Constructor.156 /// </summary>157 public PSDataCollection() : this(new List<T>())158 {159 }160 161 /// <summary>162 /// Creates a PSDataCollection that includes all the items in the IEnumerable and invokes Complete().163 /// </summary>164 /// <param name="items">165 /// Items used to initialize the collection166 /// </param>167 /// <remarks>168 /// This constructor is useful when the user wants to use an IEnumerable as an input to one of the PowerShell.BeginInvoke overloads.169 /// The invocation doesn't complete until Complete() is called on the PSDataCollection; this constructor does the Complete() on170 /// behalf of the user.171 /// </remarks>172 public PSDataCollection(IEnumerable<T> items) : this(new List<T>(items))173 {174 this.Complete();175 }176 177 /// <summary>178 /// Initializes a new instance with the specified capacity179 /// <paramref name="capacity"/>180 /// </summary>181 /// <param name="capacity">182 /// The number of elements that the new buffer can initially183 /// store.184 /// </param>185 /// <remarks>186 /// Capacity is the number of elements that the PSDataCollection can187 /// store before resizing is required.188 /// </remarks>189 public PSDataCollection(int capacity) : this(new List<T>(capacity))190 {191 }192 193 #endregion194 195 #region type converters196 197 /// <summary>198 /// Wrap the argument in a PSDataCollection.199 /// </summary>200 /// <param name="valueToConvert">The value to convert.</param>201 /// <returns>New collection of value, marked as Complete.</returns>202 [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates",203 Justification = "There are already alternates to the implicit casts, ToXXX and FromXXX methods are unnecessary and redundant")]204 public static implicit operator PSDataCollection<T>(bool valueToConvert)205 {206 return CreateAndInitializeFromExplicitValue(valueToConvert);207 }208 209 /// <summary>210 /// Wrap the argument in a PSDataCollection.211 /// </summary>212 /// <param name="valueToConvert">The value to convert.</param>213 /// <returns>New collection of value, marked as Complete.</returns>214 [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates",215 Justification = "There are already alternates to the implicit casts, ToXXX and FromXXX methods are unnecessary and redundant")]216 public static implicit operator PSDataCollection<T>(string valueToConvert)217 {218 return CreateAndInitializeFromExplicitValue(valueToConvert);219 }220 221 /// <summary>222 /// Wrap the argument in a PSDataCollection.223 /// </summary>224 /// <param name="valueToConvert">The value to convert.</param>225 /// <returns>New collection of value, marked as Complete.</returns>226 [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates",227 Justification = "There are already alternates to the implicit casts, ToXXX and FromXXX methods are unnecessary and redundant")]228 public static implicit operator PSDataCollection<T>(int valueToConvert)229 {230 return CreateAndInitializeFromExplicitValue(valueToConvert);231 }232 233 /// <summary>234 /// Wrap the argument in a PSDataCollection.235 /// </summary>236 /// <param name="valueToConvert">The value to convert.</param>237 /// <returns>New collection of value, marked as Complete.</returns>238 [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates",239 Justification = "There are already alternates to the implicit casts, ToXXX and FromXXX methods are unnecessary and redundant")]240 public static implicit operator PSDataCollection<T>(byte valueToConvert)241 {242 return CreateAndInitializeFromExplicitValue(valueToConvert);243 }244 245 private static PSDataCollection<T> CreateAndInitializeFromExplicitValue(object valueToConvert)246 {247 PSDataCollection<T> psdc = new PSDataCollection<T>();248 psdc.Add(LanguagePrimitives.ConvertTo<T>(valueToConvert));249 psdc.Complete();250 return psdc;251 }252 253 /// <summary>254 /// Wrap the argument in a PSDataCollection.255 /// </summary>256 /// <param name="valueToConvert">The value to convert.</param>257 /// <returns>New collection of value, marked as Complete.</returns>258 [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates",259 Justification = "There are already alternates to the implicit casts, ToXXX and FromXXX methods are unnecessary and redundant")]260 public static implicit operator PSDataCollection<T>(Hashtable valueToConvert)261 {262 PSDataCollection<T> psdc = new PSDataCollection<T>();263 psdc.Add(LanguagePrimitives.ConvertTo<T>(valueToConvert));264 psdc.Complete();265 return psdc;266 }267 268 /// <summary>269 /// Wrap the argument in a PSDataCollection.270 /// </summary>271 /// <param name="valueToConvert">The value to convert.</param>272 /// <returns>New collection of value, marked as Complete.</returns>273 [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates",274 Justification = "There are already alternates to the implicit casts, ToXXX and FromXXX methods are unnecessary and redundant")]275 public static implicit operator PSDataCollection<T>(T valueToConvert)276 {277 PSDataCollection<T> psdc = new PSDataCollection<T>();278 psdc.Add(LanguagePrimitives.ConvertTo<T>(valueToConvert));279 psdc.Complete();280 return psdc;281 }282 283 /// <summary>284 /// Wrap the argument in a PSDataCollection.285 /// </summary>286 /// <param name="arrayToConvert">The value to convert.</param>287 /// <returns>New collection of value, marked as Complete.</returns>288 [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates",289 Justification = "There are already alternates to the implicit casts, ToXXX and FromXXX methods are unnecessary and redundant")]290 public static implicit operator PSDataCollection<T>(object[] arrayToConvert)291 {292 PSDataCollection<T> psdc = new PSDataCollection<T>();293 if (arrayToConvert != null)294 {295 foreach (var ae in arrayToConvert)296 {297 psdc.Add(LanguagePrimitives.ConvertTo<T>(ae));298 }299 }300 301 psdc.Complete();302 return psdc;303 }304 305 #endregion306 307 #region Internal Constructor308 309 /// <summary>310 /// Construct the DataBuffer using the supplied <paramref name="listToUse"/>311 /// as the data buffer.312 /// </summary>313 /// <param name="listToUse">314 /// buffer where the elements are stored315 /// </param>316 /// <remarks>317 /// Using this constructor will make the data buffer a wrapper on318 /// top of the <paramref name="listToUse"/>, which provides synchronized319 /// access.320 /// </remarks>321 internal PSDataCollection(IList<T> listToUse)322 {323 _data = listToUse;324 }325 326 /// <summary>327 /// Creates a PSDataCollection from an ISerializable context.328 /// </summary>329 /// <param name="info">Serialization information for this instance.</param>330 /// <param name="context">The streaming context for this instance.</param>331 protected PSDataCollection(SerializationInfo info, StreamingContext context)332 {333 if (info == null)334 {335 throw PSTraceSource.NewArgumentNullException(nameof(info));336 }337 338 if (info.GetValue("Data", typeof(IList<T>)) is not IList<T> listToUse)339 {340 throw PSTraceSource.NewArgumentNullException(nameof(info));341 }342 343 _data = listToUse;344 345 _blockingEnumerator = info.GetBoolean("BlockingEnumerator");346 _dataAddedFrequency = info.GetInt32("DataAddedCount");347 EnumeratorNeverBlocks = info.GetBoolean("EnumeratorNeverBlocks");348 _isOpen = info.GetBoolean("IsOpen");349 }350 351 #endregion352 353 #region PSDataCollection Specific Public Methods / Properties354 355 /// <summary>356 /// Event fired when objects are being added to the underlying buffer.357 /// </summary>358 public event EventHandler<DataAddingEventArgs> DataAdding;359 360 /// <summary>361 /// Event fired when objects are done being added to the underlying buffer.362 /// </summary>363 public event EventHandler<DataAddedEventArgs> DataAdded;364 365 /// <summary>366 /// Event fired when the buffer is completed.367 /// </summary>368 public event EventHandler Completed;369 370 /// <summary>371 /// A boolean which determines if the buffer is open.372 /// </summary>373 public bool IsOpen374 {375 get376 {377 lock (SyncObject)378 {379 return _isOpen;380 }381 }382 }383 384 /// <summary>385 /// An int that tells the frequency of Data Added events fired.386 /// Raises the DataAdded event only when data has been added a multiple of this many times,387 /// or when collection can receive no more data, if further data is added past the last event388 /// prior to completion.389 /// </summary>390 public int DataAddedCount391 {392 get393 {394 return _dataAddedFrequency;395 }396 397 set398 {399 bool raiseDataAdded = false;400 lock (SyncObject)401 {402 _dataAddedFrequency = value;403 if (_countNewData >= _dataAddedFrequency)404 {405 raiseDataAdded = true;406 _countNewData = 0;407 }408 }409 410 if (raiseDataAdded)411 {412 // We should raise the event outside of the lock413 // as the call is made into 3rd party code414 RaiseDataAddedEvent(_lastPsInstanceId, _lastIndex);415 }416 }417 }418 419 /// <summary>420 /// Serializes all input by default.421 /// This is supported only for PSDataCollections of PSObject.422 /// </summary>423 public bool SerializeInput424 {425 get426 {427 return _serializeInput;428 }429 430 set431 {432 if (typeof(T) != typeof(PSObject))433 {434 // If you drop this constraint, GetSerializedInput must be updated.435 throw new NotSupportedException(PSDataBufferStrings.SerializationNotSupported);436 }437 438 _serializeInput = value;439 }440 }441 442 private bool _serializeInput = false;443 444 /// <summary>445 /// Determines whether this PSDataCollection was created implicitly in support of446 /// data collection (for example, a workflow that wants to capture output but hasn't447 /// provided an instance of the PSDataCollection to capture it with.)448 /// </summary>449 public bool IsAutoGenerated450 {451 get; set;452 }453 454 /// <summary>455 /// Internal tag for indicating a source object identifier for this collection.456 /// </summary>457 internal Guid SourceId458 {459 get460 {461 lock (SyncObject)462 {463 return _sourceGuid;464 }465 }466 467 set468 {469 lock (SyncObject)470 {471 _sourceGuid = value;472 }473 }474 }475 476 /// <summary>477 /// If this flag is set to true, the items in the collection will be set to null when it is478 /// traversed using a PSDataCollectionEnumerator.479 /// </summary>480 internal bool ReleaseOnEnumeration481 {482 get483 {484 lock (SyncObject)485 {486 return _releaseOnEnumeration;487 }488 }489 490 set491 {492 lock (SyncObject)493 {494 _releaseOnEnumeration = value;495 }496 }497 }498 499 /// <summary>500 /// This flag is true when the collection has been enumerated at least once by a PSDataCollectionEnumerator.501 /// </summary>502 internal bool IsEnumerated503 {504 get505 {506 lock (SyncObject)507 {508 return _isEnumerated;509 }510 }511 512 set513 {514 lock (SyncObject)515 {516 _isEnumerated = value;517 }518 }519 }520 521 /// <summary>522 /// Completes insertions to the buffer.523 /// Subsequent Inserts to the buffer will result in an InvalidOperationException.524 /// </summary>525 public void Complete()526 {527 bool raiseEvents = false;528 bool raiseDataAdded = false;529 try530 {531 // Close the buffer532 lock (SyncObject)533 {534 if (_isOpen)535 {536 _isOpen = false;537 raiseEvents = true;538 // release any threads to notify an event. Enumerator539 // blocks on this syncObject.540 Monitor.PulseAll(SyncObject);541 542 if (_countNewData > 0)543 {544 raiseDataAdded = true;545 _countNewData = 0;546 }547 }548 }549 }550 finally551 {552 // raise the events outside of the lock.553 if (raiseEvents)554 {555 // unblock any readers waiting on the handle556 _readWaitHandle?.Set();557 558 // A temporary variable is used as the Completed may559 // reach null (because of -='s) after the null check560 Completed?.Invoke(this, EventArgs.Empty);561 }562 563 if (raiseDataAdded)564 {565 RaiseDataAddedEvent(_lastPsInstanceId, _lastIndex);566 }567 }568 }569 570 /// <summary>571 /// Indicates whether the data collection should572 /// have a blocking enumerator by default. Currently573 /// only when a PowerShell object is associated with574 /// the data collection, a reference count is added575 /// which causes the enumerator to be blocking. This576 /// prevents the use of PSDataCollection without a577 /// PowerShell object. This property fixes the same.578 /// </summary>579 public bool BlockingEnumerator580 {581 get582 {583 lock (SyncObject)584 {585 return _blockingEnumerator;586 }587 }588 589 set590 {591 lock (SyncObject)592 {593 _blockingEnumerator = value;594 595 if (_blockingEnumerator)596 {597 if (!_refCountIncrementedForBlockingEnumerator)598 {599 _refCountIncrementedForBlockingEnumerator = true;600 AddRef();601 }602 }603 else604 {605 // TODO: false doesn't always leading to non-blocking606 // behavior in an intuitive way. Need to follow up607 // and fix this608 if (_refCountIncrementedForBlockingEnumerator)609 {610 _refCountIncrementedForBlockingEnumerator = false;611 DecrementRef();612 }613 }614 }615 }616 }617 618 /// <summary>619 /// If this is set to true, then the enumerator returned from620 /// GetEnumerator() will never block.621 /// </summary>622 public bool EnumeratorNeverBlocks { get; set; }623 624 #endregion625 626 #region IList Generic Overrides627 628 /// <summary>629 /// Gets or sets the element at the specified index.630 /// </summary>631 /// <param name="index">632 /// The zero-based index of the element to get or set.633 /// </param>634 /// <exception cref="InvalidOperationException">635 /// Objects cannot be added to a closed buffer.636 /// Make sure the buffer is open for Add and Insert637 /// operations to succeed.638 /// </exception>639 /// <exception cref="ArgumentOutOfRangeException">640 /// index is less than 0.641 /// (or)642 /// index is equal to or greater than Count.643 /// </exception>644 public T this[int index]645 {646 get647 {648 lock (SyncObject)649 {650 return _data[index];651 }652 }653 654 set655 {656 lock (SyncObject)657 {658 if ((index < 0) || (index >= _data.Count))659 {660 throw PSTraceSource.NewArgumentOutOfRangeException(nameof(index), index,661 PSDataBufferStrings.IndexOutOfRange, 0, _data.Count - 1);662 }663 664 if (_serializeInput)665 {666 value = (T)(object)GetSerializedObject(value);667 }668 669 _data[index] = value;670 }671 }672 }673 674 /// <summary>675 /// Determines the index of a specific item in the buffer.676 /// </summary>677 /// <param name="item">678 /// The object to locate in the buffer.679 /// </param>680 /// <returns>681 /// The index of item if found in the buffer; otherwise, -1.682 /// </returns>683 public int IndexOf(T item)684 {685 lock (SyncObject)686 {687 return InternalIndexOf(item);688 }689 }690 691 /// <summary>692 /// Inserts an item to the buffer at the specified index.693 /// </summary>694 /// <param name="index">695 /// The zero-based index at which item should be inserted.696 /// </param>697 /// <param name="item">698 /// The object to insert into the buffer.699 /// </param>700 /// <exception cref="InvalidOperationException">701 /// Objects cannot be added to a closed buffer.702 /// Make sure the buffer is open for Add and Insert703 /// operations to succeed.704 /// </exception>705 /// <exception cref="ArgumentOutOfRangeException">706 /// The index specified is less than zero or greater707 /// than Count.708 /// </exception>709 public void Insert(int index, T item)710 {711 lock (SyncObject)712 {713 InternalInsertItem(Guid.Empty, index, item);714 }715 716 RaiseEvents(Guid.Empty, index);717 }718 719 /// <summary>720 /// Removes the item at the specified index.721 /// </summary>722 /// <param name="index">723 /// The zero-based index of the item to remove.724 /// </param>725 /// <exception cref="ArgumentOutOfRangeException">726 /// index is not a valid index in the buffer.727 /// </exception>728 public void RemoveAt(int index)729 {730 lock (SyncObject)731 {732 if ((index < 0) || (index >= _data.Count))733 {734 throw PSTraceSource.NewArgumentOutOfRangeException(nameof(index), index,735 PSDataBufferStrings.IndexOutOfRange, 0, _data.Count - 1);736 }737 738 RemoveItem(index);739 }740 }741 742 #endregion743 744 #region ICollection Generic Overrides745 746 /// <summary>747 /// Gets the number of elements contained in the buffer.748 /// </summary>749 public int Count750 {751 get752 {753 lock (SyncObject)754 {755 if (_data == null)756 return 0;757 else758 return _data.Count;759 }760 }761 }762 763 /// <summary>764 /// Gets a value indicating whether the buffer is read-only.765 /// </summary>766 public bool IsReadOnly767 {768 get769 {770 return false;771 }772 }773 774 /// <summary>775 /// Adds an item to the thread-safe buffer.776 /// </summary>777 /// <param name="item">778 /// item to add779 /// </param>780 /// <exception cref="InvalidOperationException">781 /// Objects cannot be added to a closed buffer.782 /// Make sure the buffer is open for Add and Insert783 /// operations to succeed.784 /// </exception>785 public void Add(T item)786 {787 InternalAdd(Guid.Empty, item);788 }789 790 /// <summary>791 /// Removes all items from the buffer.792 /// </summary>793 public void Clear()794 {795 lock (SyncObject)796 {797 _data?.Clear();798 }799 }800 801 /// <summary>802 /// Determines whether the buffer contains an element with a specific value.803 /// </summary>804 /// <param name="item">805 /// The object to locate in the buffer.806 /// </param>807 /// <returns>808 /// true if the element value is found in the buffer; otherwise false.809 /// </returns>810 public bool Contains(T item)811 {812 lock (SyncObject)813 {814 if (_serializeInput)815 {816 item = (T)(object)GetSerializedObject(item);817 }818 819 return _data.Contains(item);820 }821 }822 823 /// <summary>824 /// Copies the elements of the buffer to a specified array, starting at a particular index.825 /// </summary>826 /// <param name="array">827 /// The destination Array for the elements of type T copied from the buffer.828 /// </param>829 /// <param name="arrayIndex">830 /// The zero-based index in the array at which copying begins.831 /// </param>832 /// <exception cref="ArgumentException">833 /// array is multidimensional.834 /// (or)835 /// arrayIndex is equal to or greater than the length of array.836 /// (or)837 /// The number of elements in the source buffer is greater than the838 /// available space from arrayIndex to the end of the destination array.839 /// (or)840 /// Type T cannot be cast automatically to the type of the destination array.841 /// </exception>842 /// <exception cref="ArgumentNullException">843 /// array is a null reference844 /// </exception>845 /// <exception cref="ArgumentOutOfRangeException">846 /// arrayIndex is less than 0.847 /// </exception>848 public void CopyTo(T[] array, int arrayIndex)849 {850 lock (SyncObject)851 {852 _data.CopyTo(array, arrayIndex);853 }854 }855 856 /// <summary>857 /// Removes the first occurrence of a specified item from the buffer.858 /// </summary>859 /// <param name="item">860 /// The object to remove from the buffer.861 /// </param>862 /// <returns>863 /// true if item was successfully removed from the buffer; otherwise, false.864 /// </returns>865 public bool Remove(T item)866 {867 lock (SyncObject)868 {869 int index = InternalIndexOf(item);870 if (index < 0)871 {872 return false;873 }874 875 RemoveItem(index);876 return true;877 }878 }879 880 #endregion881 882 #region IEnumerable Generic Overrides883 884 /// <summary>885 /// Returns an enumerator that iterates through the886 /// elements of the buffer.887 /// </summary>888 /// <returns>889 /// An IEnumerator for objects of the type stored in the buffer.890 /// </returns>891 public IEnumerator<T> GetEnumerator()892 {893 return new PSDataCollectionEnumerator<T>(this, EnumeratorNeverBlocks);894 }895 896 #endregion897 898 #region IList Overrides899 900 /// <summary>901 /// Adds an element to the buffer.902 /// </summary>903 /// <param name="value">904 /// The object to add to the buffer.905 /// </param>906 /// <returns>907 /// The position into which the new element was inserted.908 /// </returns>909 /// <exception cref="InvalidOperationException">910 /// Objects cannot be added to a closed buffer.911 /// Make sure the buffer is open for Add and Insert912 /// operations to succeed.913 /// </exception>914 /// <exception cref="ArgumentException">915 /// value reference is null.916 /// (or)917 /// value is not of the correct generic type T for the buffer.918 /// </exception>919 int IList.Add(object value)920 {921 PSDataCollection<T>.VerifyValueType(value);922 int index = _data.Count;923 InternalAdd(Guid.Empty, (T)value);924 RaiseEvents(Guid.Empty, index);925 926 return index;927 }928 929 /// <summary>930 /// Determines whether the collection contains an931 /// element with a specific value.932 /// </summary>933 /// <param name="value">934 /// The object to locate in the collection935 /// </param>936 /// <returns>937 /// true if the element value is found in the collection;938 /// otherwise false.939 /// </returns>940 /// <exception cref="ArgumentException">941 /// value reference is null.942 /// (or)943 /// value is not of the correct generic type T for the buffer.944 /// </exception>945 bool IList.Contains(object value)946 {947 PSDataCollection<T>.VerifyValueType(value);948 return Contains((T)value);949 }950 951 /// <summary>952 /// Determines the zero-based index of an element in the buffer.953 /// </summary>954 /// <param name="value">955 /// The element in the buffer whose index is being determined.956 /// </param>957 /// <returns>958 /// The index of the value if found in the buffer; otherwise, -1.959 /// </returns>960 /// <exception cref="ArgumentException">961 /// value reference is null.962 /// (or)963 /// value is not of the correct generic type T for the buffer.964 /// </exception>965 int IList.IndexOf(object value)966 {967 PSDataCollection<T>.VerifyValueType(value);968 return IndexOf((T)value);969 }970 971 /// <summary>972 /// Inserts an object into the buffer at a specified index.973 /// </summary>974 /// <param name="index">975 /// The zero-based index at which value is to be inserted.976 /// </param>977 /// <param name="value">978 /// The object to insert into the buffer.979 /// </param>980 /// <exception cref="ArgumentOutOfRangeException">981 /// index is not a valid index in the buffer.982 /// </exception>983 /// <exception cref="ArgumentException">984 /// value reference is null.985 /// (or)986 /// value is not of the correct generic type T for the buffer.987 /// </exception>988 void IList.Insert(int index, object value)989 {990 PSDataCollection<T>.VerifyValueType(value);991 Insert(index, (T)value);992 }993 994 /// <summary>995 /// Removes the first occurrence of a specified object996 /// as an element from the buffer.997 /// </summary>998 /// <param name="value">999 /// The object to be removed from the buffer.1000 /// </param>1001 /// <exception cref="ArgumentException">1002 /// value reference is null.1003 /// (or)1004 /// value is not of the correct generic type T for the buffer.1005 /// </exception>1006 void IList.Remove(object value)1007 {1008 PSDataCollection<T>.VerifyValueType(value);1009 Remove((T)value);1010 }1011 1012 /// <summary>1013 /// Gets a value that indicates whether the buffer is fixed in size.1014 /// </summary>1015 bool IList.IsFixedSize1016 {1017 get1018 {1019 return false;1020 }1021 }1022 1023 /// <summary>1024 /// Gets a value that indicates whether the buffer is read-only.1025 /// </summary>1026 bool IList.IsReadOnly1027 {1028 get1029 {1030 return false;1031 }1032 }1033 1034 /// <summary>1035 /// Gets or sets the element at the specified index.1036 /// </summary>1037 /// <param name="index">1038 /// The zero-based index of the element to get or set.1039 /// </param>1040 /// <exception cref="IndexOutOfRangeException">1041 /// index is less than 0.1042 /// (or)1043 /// index is equal to or greater than Count.1044 /// </exception>1045 /// <exception cref="ArgumentException">1046 /// value reference is null.1047 /// (or)1048 /// value is not of the correct generic type T for the buffer.1049 /// </exception>1050 object IList.this[int index]1051 {1052 get1053 {1054 return this[index];1055 }1056 1057 set1058 {1059 PSDataCollection<T>.VerifyValueType(value);1060 this[index] = (T)value;1061 }1062 }1063 1064 #endregion1065 1066 #region ICollection Overrides1067 1068 /// <summary>1069 /// Gets a value that indicates whether the buffer is synchronized.1070 /// </summary>1071 bool ICollection.IsSynchronized1072 {1073 get1074 {1075 return true;1076 }1077 }1078 1079 /// <summary>1080 /// Gets the object used to synchronize access to the thread-safe buffer.1081 /// </summary>1082 object ICollection.SyncRoot1083 {1084 get1085 {1086 return SyncObject;1087 }1088 }1089 1090 /// <summary>1091 /// Copies the elements of the collection to a specified array,1092 /// starting at a particular index.1093 /// </summary>1094 /// <param name="array">1095 /// The destination Array for the elements of type T copied1096 /// from the buffer.1097 /// </param>1098 /// <param name="index">1099 /// The zero-based index in the array at which copying begins.1100 /// </param>1101 /// <exception cref="ArgumentException">1102 /// array is multidimensional.1103 /// (or)1104 /// arrayIndex is equal to or greater than the length of array.1105 /// (or)1106 /// The number of elements in the source buffer is greater than the1107 /// available space from arrayIndex to the end of the destination array.1108 /// </exception>1109 /// <exception cref="ArgumentNullException">1110 /// array is a null reference1111 /// </exception>1112 /// <exception cref="ArgumentOutOfRangeException">1113 /// arrayIndex is less than 0.1114 /// </exception>1115 void ICollection.CopyTo(Array array, int index)1116 {1117 lock (SyncObject)1118 {1119 _data.CopyTo((T[])array, index);1120 }1121 }1122 1123 #endregion1124 1125 #region IEnumerable Overrides1126 1127 /// <summary>1128 /// Returns an enumerator that iterates through the buffer.1129 /// </summary>1130 /// <returns>1131 /// An IEnumerator for objects of the type stored in the buffer.1132 /// </returns>1133 IEnumerator IEnumerable.GetEnumerator()1134 {1135 return new PSDataCollectionEnumerator<T>(this, EnumeratorNeverBlocks);1136 }1137 1138 #endregion1139 1140 #region Streaming Behavior1141 1142 /// <summary>1143 /// Makes a shallow copy of all the elements currently in this collection1144 /// and clears them from this collection. This will not result in a blocking call.1145 ///1146 /// Calling this method might have side effects on the enumerator. When this1147 /// method is called, the behavior of the enumerator is not defined.1148 /// </summary>1149 /// <returns>1150 /// A new collection with a copy of all the elements in the current collection.1151 /// </returns>1152 public Collection<T> ReadAll()1153 {1154 return ReadAndRemove(0);1155 }1156 1157 /// <summary>1158 /// Makes a shallow copy of all the elements currently in this collection1159 /// and clears them from this collection. This will not result in a blocking call.1160 ///1161 /// Calling this method might have side effects on the enumerator. When this1162 /// method is called, the behavior of the enumerator is not defined.1163 /// </summary>1164 /// <returns>1165 /// A new collection with a copy of all the elements in the current collection.1166 /// </returns>1167 /// <param name="readCount">Maximum number of elements to read.</param>1168 internal Collection<T> ReadAndRemove(int readCount)1169 {1170 Dbg.Assert(_data != null, "Collection cannot be null");1171 1172 Dbg.Assert(readCount >= 0, "ReadCount cannot be negative");1173 1174 int resolvedReadCount = (readCount > 0 ? readCount : Int32.MaxValue);1175 1176 lock (SyncObject)1177 {1178 // Copy the elements into a new collection1179 // and clear.1180 Collection<T> result = new Collection<T>();1181 1182 for (int i = 0; i < resolvedReadCount; i++)1183 {1184 if (_data.Count > 0)1185 {1186 result.Add(_data[0]);1187 _data.RemoveAt(0);1188 }1189 else1190 {1191 break;1192 }1193 }1194 1195 if (_readWaitHandle != null)1196 {1197 if (_data.Count > 0 || !_isOpen)1198 {1199 // release all the waiting threads.1200 _readWaitHandle.Set();