Skip to content

Commit 7b6345b

Browse files
Improvements in disposed object exceptions.
1 parent 2aa08aa commit 7b6345b

39 files changed

+917
-333
lines changed

benchmarking/Program.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ static void Main()
2020
//TestEntry.Test1();
2121
//TestEntry.Test2();
2222
//QueueTests();
23-
ListTests();
23+
//ListTests();
2424
DictionaryTests();
2525

2626
Console.Beep();
@@ -173,6 +173,7 @@ static void HashSetTests()
173173

174174
report.AddBenchmark("LockSynchronizedHashSet",
175175
_ => () => new LockSynchronizedHashSet<object>());
176+
176177
report.AddBenchmark("ReadWriteSynchronizedHashSet",
177178
_ => () => new ReadWriteSynchronizedHashSet<object>());
178179

@@ -194,13 +195,12 @@ static void DictionaryTests()
194195

195196
report.AddBenchmark("LockSynchronized Dictionary",
196197
_ => () => new LockSynchronizedDictionary<int, object>());
197-
//report.AddBenchmark("ReadWriteSynchronized Dictionary",
198-
// _ => () => new ReadWriteSynchronizedDictionaryWrapper<int, object>());
199198

200199
report.AddBenchmark("LockSynchronized OrderedDictionary",
201200
_ => () => new LockSynchronizedOrderedDictionary<int, object>());
202-
//report.AddBenchmark("ReadWriteSynchronized OrderedDictionary",
203-
// _ => () => new ReadWriteSynchronizedDictionaryWrapper<int, object>(new OrderedDictionary<int, object>()));
201+
202+
report.AddBenchmark("LockSynchronized IndexedDictionary",
203+
_ => () => new LockSynchronizedIndexedDictionary<int, object>());
204204

205205
report.Pretest(200, 200); // Run once through first to scramble/warm-up initial conditions.
206206

source/CollectionWrapper.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,16 @@ public CollectionWrapper(TCollection source, bool owner = false)
2525
#region Implementation of ICollection<T>
2626

2727
[MethodImpl(MethodImplOptions.AggressiveInlining)]
28-
protected virtual void AddInternal(T item)
28+
protected virtual void AddInternal(in T item)
2929
=> InternalSource.Add(item);
3030

3131
/// <inheritdoc />
3232
[MethodImpl(MethodImplOptions.AggressiveInlining)]
33-
public virtual void Add(T item) => AddInternal(item);
33+
public virtual void Add(T item)
34+
{
35+
AssertIsAlive();
36+
AddInternal(in item);
37+
}
3438

3539
/// <inheritdoc cref="IAddMultiple{T}.AddThese(T, T, T[])"/>
3640
public virtual void AddThese(T item1, T item2, params T[] items)

source/DictionaryToHashSetWrapper.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ public virtual bool Add(T item)
6868

6969
/// <inheritdoc />
7070
[ExcludeFromCodeCoverage]
71-
public IEnumerator<T> GetEnumerator() => InternalSource.Keys.GetEnumerator();
71+
public IEnumerator<T> GetEnumerator()
72+
=> InternalSource.Keys.GetEnumerator();
7273

7374
/// <inheritdoc />
7475
public void ExceptWith(IEnumerable<T> other)

source/DictionaryWrapper.cs

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,51 +7,60 @@ namespace Open.Collections;
77
/// <inheritdoc />
88
[ExcludeFromCodeCoverage]
99
public class DictionaryWrapper<TKey, TValue>
10-
: CollectionWrapper<KeyValuePair<TKey, TValue>, IDictionary<TKey, TValue>>, IDictionary<TKey, TValue>
10+
: DictionaryWrapperBase<TKey, TValue, IDictionary<TKey, TValue>>
1111
{
1212
/// <inheritdoc />
13-
public DictionaryWrapper(int capacity = 0)
14-
: base(new Dictionary<TKey, TValue>(capacity), true)
15-
{
16-
}
13+
public DictionaryWrapper()
14+
: base(new Dictionary<TKey, TValue>(), true) { }
1715

16+
/// <inheritdoc />
17+
public DictionaryWrapper(int capacity)
18+
: base(new Dictionary<TKey, TValue>(capacity), true) { }
19+
20+
/// <inheritdoc />
1821
public DictionaryWrapper(IDictionary<TKey, TValue> source, bool owned = false)
1922
: base(source, owned)
2023
{
2124
}
2225

26+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2327
/// <inheritdoc />
24-
public virtual TValue this[TKey key]
25-
{
26-
get => InternalSource[key];
27-
set => InternalSource[key] = value;
28-
}
28+
protected override TValue GetValueInternal(TKey key)
29+
=> InternalSource[key];
2930

31+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
3032
/// <inheritdoc />
31-
public virtual ICollection<TKey> Keys
32-
=> InternalSource.Keys;
33+
protected override void SetValueInternal(TKey key, TValue value)
34+
=> InternalSource[key] = value;
3335

34-
/// <inheritdoc />
35-
public virtual ICollection<TValue> Values
36-
=> InternalSource.Values;
36+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
37+
protected override ICollection<TKey> GetKeys()
38+
=> new ReadOnlyCollectionAdapter<TKey>(
39+
ThrowIfDisposed(InternalSource.Keys),
40+
() => InternalSource.Count);
3741

3842
[MethodImpl(MethodImplOptions.AggressiveInlining)]
39-
/// <inheritdoc />
40-
public virtual void Add(TKey key, TValue value)
41-
=> InternalSource.Add(key, value);
43+
protected override ICollection<TValue> GetValues()
44+
=> new ReadOnlyCollectionAdapter<TValue>(
45+
ThrowIfDisposed(InternalSource.Values),
46+
() => InternalSource.Count);
4247

4348
[MethodImpl(MethodImplOptions.AggressiveInlining)]
49+
protected override void AddInternal(TKey key, TValue value)
50+
=> InternalSource.Add(key, value);
51+
4452
/// <inheritdoc />
45-
public virtual bool ContainsKey(TKey key)
53+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
54+
public override bool ContainsKey(TKey key)
4655
=> InternalSource.ContainsKey(key);
4756

48-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
4957
/// <inheritdoc />
50-
public virtual bool Remove(TKey key)
58+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
59+
public override bool Remove(TKey key)
5160
=> InternalSource.Remove(key);
5261

53-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
5462
/// <inheritdoc />
55-
public bool TryGetValue(TKey key, out TValue value)
63+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
64+
public override bool TryGetValue(TKey key, out TValue value)
5665
=> InternalSource.TryGetValue(key, out value);
5766
}

source/DictionaryWrapperBase.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System.Collections.Generic;
2+
using System.Diagnostics.CodeAnalysis;
3+
using System.Runtime.CompilerServices;
4+
5+
namespace Open.Collections;
6+
7+
[ExcludeFromCodeCoverage]
8+
public abstract class DictionaryWrapperBase<TKey, TValue, TCollection>
9+
: CollectionWrapper<KeyValuePair<TKey, TValue>, TCollection>, IDictionary<TKey, TValue>
10+
where TCollection : class, ICollection<KeyValuePair<TKey, TValue>>
11+
{
12+
protected DictionaryWrapperBase(TCollection source, bool owner = false)
13+
: base(source, owner)
14+
{
15+
}
16+
17+
/// <inheritdoc />
18+
public TValue this[TKey key]
19+
{
20+
get => GetValueInternal(key);
21+
set => SetValueInternal(key, value);
22+
}
23+
24+
protected abstract TValue GetValueInternal(TKey key);
25+
26+
protected abstract void SetValueInternal(TKey key, TValue value);
27+
28+
ICollection<TKey>? _keys;
29+
/// <inheritdoc />
30+
public ICollection<TKey> Keys => _keys ??= GetKeys();
31+
protected abstract ICollection<TKey> GetKeys();
32+
33+
ICollection<TValue>? _values;
34+
35+
/// <inheritdoc />
36+
public ICollection<TValue> Values => _values ??= GetValues();
37+
38+
protected abstract ICollection<TValue> GetValues();
39+
40+
protected abstract void AddInternal(TKey key, TValue value);
41+
42+
/// <inheritdoc />
43+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
44+
public void Add(TKey key, TValue value)
45+
=> AddInternal(key, value);
46+
47+
/// <inheritdoc />
48+
public abstract bool ContainsKey(TKey key);
49+
50+
/// <inheritdoc />
51+
public abstract bool Remove(TKey key);
52+
53+
/// <inheritdoc />
54+
public abstract bool TryGetValue(TKey key, out TValue value);
55+
}

source/Extensions.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,4 +980,53 @@ public static ReadOnlyCollection<T> ToReadOnlyCollection<T>(this ReadOnlyMemory<
980980
/// <inheritdoc cref="ToImmutableArray{T}(ReadOnlyMemory{T})"/>
981981
public static ReadOnlyCollection<T> ToReadOnlyCollection<T>(this Memory<T> memory)
982982
=> memory.Span.ToReadOnlyCollection();
983+
984+
/// <summary>
985+
/// Executes an action before the enumerable is consumed.
986+
/// </summary>
987+
public static IEnumerable<T> Preflight<T>(
988+
this IEnumerable<T> source,
989+
Action before)
990+
{
991+
before();
992+
foreach (var item in source)
993+
yield return item;
994+
}
995+
996+
/// <summary>
997+
/// Executes an action before the enumerable is consumed.
998+
/// </summary>
999+
public static IEnumerator<T> Preflight<T>(
1000+
this IEnumerator<T> source,
1001+
Action before)
1002+
{
1003+
before();
1004+
while (source.MoveNext())
1005+
yield return source.Current;
1006+
}
1007+
1008+
public static IEnumerable<T> BeforeGetEnumerator<T>(
1009+
this IEnumerable<T> source,
1010+
Action before)
1011+
=> new PreflightEnumerable<T>(source, before);
1012+
1013+
private class PreflightEnumerable<T> : IEnumerable<T>
1014+
{
1015+
private readonly IEnumerable<T> _source;
1016+
private readonly Action _before;
1017+
1018+
public PreflightEnumerable(IEnumerable<T> source, Action before)
1019+
{
1020+
_source = source ?? throw new ArgumentNullException(nameof(source));
1021+
_before = before ?? throw new ArgumentNullException(nameof(before));
1022+
}
1023+
1024+
public IEnumerator<T> GetEnumerator()
1025+
{
1026+
_before();
1027+
return _source.GetEnumerator();
1028+
}
1029+
1030+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
1031+
}
9831032
}

source/IOrderedDictionary.cs renamed to source/IIndexedDictionary.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,28 @@ namespace Open.Collections;
88
/// Represents a generic items of key/value pairs that are ordered independently of the key and value.
99
/// </summary>
1010
/// <inheritdoc />
11-
public interface IOrderedDictionary<TKey, TValue> : IDictionary<TKey, TValue>
11+
public interface IIndexedDictionary<TKey, TValue> : IDictionary<TKey, TValue>
1212
{
1313
/// <summary>
14-
/// Adds an entry with the specified key and value into the <see cref="IOrderedDictionary{TKey,TValue}"/>.
14+
/// Adds an entry with the specified key and value into the <see cref="IIndexedDictionary{TKey,TValue}"/>.
1515
/// </summary>
1616
/// <returns>The index of the newly added entry</returns>
1717
/// <inheritdoc cref="Insert(int, TKey, TValue)"/>
1818
new int Add(TKey key, TValue value);
1919

2020
/// <summary>
21-
/// Inserts a new entry into the <see cref="IOrderedDictionary{TKey,TValue}"/> items with the specified key and value at the specified index.
21+
/// Inserts a new entry into the <see cref="IIndexedDictionary{TKey,TValue}"/> items with the specified key and value at the specified index.
2222
/// </summary>
2323
/// <param name="index">The zero-based index at which the element should be inserted.</param>
2424
/// <param name="key">The key of the entry to add.</param>
2525
/// <param name="value">The value of the entry to add. The value can be <see langword="null"/> if the type of the values in the dictionary is a reference type.</param>
2626
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is less than 0.<br/>
2727
/// -or-<br/>
2828
/// <paramref name="index"/> is greater than <see cref="System.Collections.ICollection.Count"/>.</exception>
29-
/// <exception cref="ArgumentException">An element with the same key already exists in the <see cref="IOrderedDictionary{TKey,TValue}"/>.</exception>
30-
/// <exception cref="NotSupportedException">The <see cref="IOrderedDictionary{TKey,TValue}"/> is read-only.<br/>
29+
/// <exception cref="ArgumentException">An element with the same key already exists in the <see cref="IIndexedDictionary{TKey,TValue}"/>.</exception>
30+
/// <exception cref="NotSupportedException">The <see cref="IIndexedDictionary{TKey,TValue}"/> is read-only.<br/>
3131
/// -or-<br/>
32-
/// The <see cref="IOrderedDictionary{TKey,TValue}"/> has a fized size.</exception>
32+
/// The <see cref="IIndexedDictionary{TKey,TValue}"/> has a fized size.</exception>
3333
void Insert(int index, TKey key, TValue value);
3434

3535
/// <summary>
@@ -64,7 +64,7 @@ public interface IOrderedDictionary<TKey, TValue> : IDictionary<TKey, TValue>
6464
bool SetValueAt(int index, TValue value, out TKey key);
6565

6666
/// <summary>
67-
/// Removes the entry at the specified index from the <see cref="IOrderedDictionary{TKey,TValue}"/> items.
67+
/// Removes the entry at the specified index from the <see cref="IIndexedDictionary{TKey,TValue}"/> items.
6868
/// </summary>
6969
/// <param name="index">The zero-based index of the entry to remove.</param>
7070
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is less than 0.<br/>

0 commit comments

Comments
 (0)