| | | 1 | | // ----------------------------------------------------------------------- |
| | | 2 | | // <copyright file="SynchronizedObservableCollection.cs" company="Stéphane ANDRE"> |
| | | 3 | | // Copyright (c) Stéphane ANDRE. All rights reserved. |
| | | 4 | | // </copyright> |
| | | 5 | | // ----------------------------------------------------------------------- |
| | | 6 | | |
| | | 7 | | using System; |
| | | 8 | | using System.Collections.Generic; |
| | | 9 | | using System.Linq; |
| | | 10 | | |
| | | 11 | | namespace MyNet.Collections; |
| | | 12 | | |
| | | 13 | | /// <summary> |
| | | 14 | | /// External synchronization adapter around an observable range collection. |
| | | 15 | | /// </summary> |
| | | 16 | | /// <typeparam name="T">The item type.</typeparam> |
| | | 17 | | /// <remarks> |
| | | 18 | | /// Initializes a new instance of the <see cref="SynchronizedObservableCollection{T}"/> class with the specified inner c |
| | | 19 | | /// </remarks> |
| | | 20 | | /// <param name="inner">The inner observable range collection.</param> |
| | | 21 | | /// <param name="synchronizer">The collection synchronizer.</param> |
| | 24 | 22 | | public sealed class SynchronizedObservableCollection<T>(ObservableRangeCollection<T> inner, ICollectionSynchronizer? syn |
| | | 23 | | { |
| | 24 | 24 | | private readonly ICollectionSynchronizer _synchronizer = synchronizer ?? new LockCollectionSynchronizer(); |
| | | 25 | | |
| | | 26 | | /// <summary> |
| | | 27 | | /// Gets the number of elements contained in the collection, using the synchronizer to ensure thread-safe access. |
| | | 28 | | /// </summary> |
| | 1518 | 29 | | public override int Count => _synchronizer.Read(() => Inner.Count); |
| | | 30 | | |
| | | 31 | | /// <summary> |
| | | 32 | | /// Gets a value indicating whether the collection is read-only. This implementation always returns false, as the co |
| | | 33 | | /// </summary> |
| | 0 | 34 | | public override bool IsReadOnly => false; |
| | | 35 | | |
| | | 36 | | /// <summary> |
| | | 37 | | /// Gets or sets the element at the specified index, using the synchronizer to ensure thread-safe access for both re |
| | | 38 | | /// </summary> |
| | | 39 | | /// <param name="index">The zero-based index of the element to get or set.</param> |
| | | 40 | | /// <returns>The element at the specified index.</returns> |
| | | 41 | | public override T this[int index] |
| | | 42 | | { |
| | 3 | 43 | | get => _synchronizer.Read(() => Inner[index]); |
| | 3 | 44 | | set => _synchronizer.Write(() => Inner[index] = value); |
| | | 45 | | } |
| | | 46 | | |
| | | 47 | | /// <summary> |
| | | 48 | | /// Adds an item to the collection, using the synchronizer to ensure thread-safe access for modifications. |
| | | 49 | | /// </summary> |
| | | 50 | | /// <param name="item">The item to add to the collection.</param> |
| | 6606 | 51 | | public override void Add(T item) => _synchronizer.Write(() => Inner.Add(item)); |
| | | 52 | | |
| | | 53 | | /// <summary> |
| | | 54 | | /// Adds a range of items to the collection, using the synchronizer to ensure thread-safe access for modifications. |
| | | 55 | | /// </summary> |
| | | 56 | | /// <param name="items">The items to add to the collection.</param> |
| | 33 | 57 | | public override void AddRange(IEnumerable<T> items) => _synchronizer.Write(() => Inner.AddRange(items)); |
| | | 58 | | |
| | | 59 | | /// <summary> |
| | | 60 | | /// Removes all items from the collection, using the synchronizer to ensure thread-safe access for modifications. |
| | | 61 | | /// </summary> |
| | 0 | 62 | | public override void Clear() => _synchronizer.Write(Inner.Clear); |
| | | 63 | | |
| | | 64 | | /// <summary> |
| | | 65 | | /// Determines whether the collection contains a specific value, using the synchronizer to ensure thread-safe access |
| | | 66 | | /// </summary> |
| | | 67 | | /// <param name="item">The item to locate in the collection.</param> |
| | | 68 | | /// <returns>true if item is found in the collection; otherwise, false.</returns> |
| | 3 | 69 | | public override bool Contains(T item) => _synchronizer.Read(() => Inner.Contains(item)); |
| | | 70 | | |
| | | 71 | | /// <summary> |
| | | 72 | | /// Copies the elements of the collection to an array, starting at a particular array index, using the synchronizer |
| | | 73 | | /// </summary> |
| | | 74 | | /// <param name="array">The destination array.</param> |
| | | 75 | | /// <param name="arrayIndex">The zero-based index in array at which copying begins.</param> |
| | | 76 | | public override void CopyTo(T[] array, int arrayIndex) |
| | | 77 | | { |
| | 9 | 78 | | ArgumentNullException.ThrowIfNull(array); |
| | 6 | 79 | | _synchronizer.Read(() => Inner.CopyTo(array, arrayIndex)); |
| | 6 | 80 | | } |
| | | 81 | | |
| | | 82 | | /// <summary> |
| | | 83 | | /// Returns an enumerator that iterates through the collection. This implementation creates a snapshot of the collec |
| | | 84 | | /// </summary> |
| | | 85 | | /// <returns>An enumerator for the collection.</returns> |
| | | 86 | | public override IEnumerator<T> GetEnumerator() |
| | | 87 | | { |
| | | 88 | | // Enumerate over a snapshot to avoid holding a read lock for the whole iteration. |
| | 12 | 89 | | var snapshot = _synchronizer.Read(() => Inner.ToList()); |
| | 12 | 90 | | return snapshot.GetEnumerator(); |
| | | 91 | | } |
| | | 92 | | |
| | | 93 | | /// <summary> |
| | | 94 | | /// Determines the index of a specific item in the collection, using the synchronizer to ensure thread-safe access. |
| | | 95 | | /// </summary> |
| | | 96 | | /// <param name="item">The item to locate in the collection.</param> |
| | | 97 | | /// <returns>The index of the item if found; otherwise, -1.</returns> |
| | 3 | 98 | | public override int IndexOf(T item) => _synchronizer.Read(() => Inner.IndexOf(item)); |
| | | 99 | | |
| | | 100 | | /// <summary> |
| | | 101 | | /// Inserts an item into the collection at the specified index, using the synchronizer to ensure thread-safe access |
| | | 102 | | /// </summary> |
| | | 103 | | /// <param name="index">The zero-based index at which the item should be inserted.</param> |
| | | 104 | | /// <param name="item">The item to insert.</param> |
| | 3 | 105 | | public override void Insert(int index, T item) => _synchronizer.Write(() => Inner.Insert(index, item)); |
| | | 106 | | |
| | | 107 | | /// <summary> |
| | | 108 | | /// Inserts a range of items into the collection at the specified index, using the synchronizer to ensure thread-saf |
| | | 109 | | /// </summary> |
| | | 110 | | /// <param name="items">The items to insert.</param> |
| | | 111 | | /// <param name="index">The zero-based index at which the items should be inserted.</param> |
| | 3 | 112 | | public override void InsertRange(IEnumerable<T> items, int index) => _synchronizer.Write(() => Inner.InsertRange(ite |
| | | 113 | | |
| | | 114 | | /// <summary> |
| | | 115 | | /// Removes the first occurrence of a specific object from the collection, using the synchronizer to ensure thread-s |
| | | 116 | | /// </summary> |
| | | 117 | | /// <param name="item">The item to remove.</param> |
| | | 118 | | /// <returns>true if item was successfully removed; otherwise, false.</returns> |
| | 0 | 119 | | public override bool Remove(T item) => _synchronizer.Write(() => Inner.Remove(item)); |
| | | 120 | | |
| | | 121 | | /// <summary> |
| | | 122 | | /// Removes all the elements that match the conditions defined by the specified predicate, using the synchronizer to |
| | | 123 | | /// </summary> |
| | | 124 | | /// <param name="predicate">The predicate that defines the conditions of the elements to remove.</param> |
| | | 125 | | /// <returns>The number of elements removed.</returns> |
| | 3 | 126 | | public override int RemoveAll(Func<T, bool> predicate) => _synchronizer.Write(() => Inner.RemoveAll(predicate)); |
| | | 127 | | |
| | | 128 | | /// <summary> |
| | | 129 | | /// Removes the element at the specified index, using the synchronizer to ensure thread-safe access for modification |
| | | 130 | | /// </summary> |
| | | 131 | | /// <param name="index">The zero-based index of the element to remove.</param> |
| | 1500 | 132 | | public override void RemoveAt(int index) => _synchronizer.Write(() => Inner.RemoveAt(index)); |
| | | 133 | | |
| | | 134 | | /// <summary> |
| | | 135 | | /// Removes a range of elements from the collection, using the synchronizer to ensure thread-safe access for modific |
| | | 136 | | /// </summary> |
| | | 137 | | /// <param name="index">The zero-based starting index of the range to remove.</param> |
| | | 138 | | /// <param name="count">The number of elements to remove.</param> |
| | 3 | 139 | | public override void RemoveRange(int index, int count) => _synchronizer.Write(() => Inner.RemoveRange(index, count)) |
| | | 140 | | |
| | | 141 | | /// <summary> |
| | | 142 | | /// Loads a collection of items into the collection, using the synchronizer to ensure thread-safe access for modific |
| | | 143 | | /// </summary> |
| | | 144 | | /// <param name="items">The items to load into the collection.</param> |
| | 3 | 145 | | public override void Load(IEnumerable<T> items) => _synchronizer.Write(() => Inner.Load(items)); |
| | | 146 | | |
| | | 147 | | /// <summary> |
| | | 148 | | /// Sets the capacity of the collection, using the synchronizer to ensure thread-safe access for modifications. |
| | | 149 | | /// </summary> |
| | | 150 | | /// <param name="capacity">The new capacity of the collection.</param> |
| | 3 | 151 | | public override void SetCapacity(int capacity) => _synchronizer.Write(() => Inner.SetCapacity(capacity)); |
| | | 152 | | } |
| | | 153 | | |