-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Moved to generics #2866
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Moved to generics #2866
Changes from all commits
4f54e1e
2f16430
dcbb3a6
d4f9372
87ace66
ce20600
f0b1f00
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,15 @@ | ||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) | ||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Stride.Core.Collections; | ||
|
||
public interface ITrackingCollectionChanged | ||
public interface ITrackingCollectionChanged<TValue> | ||
{ | ||
/// <summary> | ||
/// Occurs when [collection changed]. | ||
/// </summary> | ||
/// Called as is when adding an item, and in reverse-order when removing an item. | ||
event EventHandler<TrackingCollectionChangedEventArgs> CollectionChanged; | ||
event EventHandler<TrackingCollectionChangedEventArgs<TValue>> CollectionChanged; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) | ||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. | ||
|
||
namespace Stride.Core.Collections; | ||
|
||
public interface ITrackingKeyedCollectionChanged<TKey, TValue> | ||
{ | ||
/// <summary> | ||
/// Occurs when [collection changed]. | ||
/// </summary> | ||
/// Called as is when adding an item, and in reverse-order when removing an item. | ||
event EventHandler<TrackingKeyedCollectionChangedEventArgs<TKey, TValue>> CollectionChanged; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,38 +12,38 @@ namespace Stride.Core.Collections; | |
/// </summary> | ||
/// <typeparam name="T">The type of elements in the collection.</typeparam> | ||
[DataSerializer(typeof(ListAllSerializer<,>), Mode = DataSerializerGenericMode.TypeAndGenericArguments)] | ||
public class TrackingCollection<T> : FastCollection<T>, ITrackingCollectionChanged | ||
public class TrackingCollection<T> : FastCollection<T>, ITrackingCollectionChanged<T> | ||
{ | ||
private EventHandler<TrackingCollectionChangedEventArgs>? itemAdded; | ||
private EventHandler<TrackingCollectionChangedEventArgs>? itemRemoved; | ||
private EventHandler<TrackingCollectionChangedEventArgs<T>>? _itemAdded; | ||
private EventHandler<TrackingCollectionChangedEventArgs<T>>? _itemRemoved; | ||
Comment on lines
+17
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrong naming convention There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah my mistake, I thought we were going to use the Microsoft standards for new changes if we worked in them. Ill switch them back to the lower camel case structure. |
||
|
||
/// <inheritdoc/> | ||
public event EventHandler<TrackingCollectionChangedEventArgs> CollectionChanged | ||
public event EventHandler<TrackingCollectionChangedEventArgs<T>> CollectionChanged | ||
{ | ||
add | ||
{ | ||
// We keep a list in reverse order for removal, so that we can easily have multiple handlers depending on each others | ||
itemAdded = (EventHandler<TrackingCollectionChangedEventArgs>)Delegate.Combine(itemAdded, value); | ||
itemRemoved = (EventHandler<TrackingCollectionChangedEventArgs>)Delegate.Combine(value, itemRemoved); | ||
_itemAdded = (EventHandler<TrackingCollectionChangedEventArgs<T>>)Delegate.Combine(_itemAdded, value); | ||
_itemRemoved = (EventHandler<TrackingCollectionChangedEventArgs<T>>)Delegate.Combine(value, _itemRemoved); | ||
} | ||
remove | ||
{ | ||
itemAdded = (EventHandler<TrackingCollectionChangedEventArgs>?)Delegate.Remove(itemAdded, value); | ||
itemRemoved = (EventHandler<TrackingCollectionChangedEventArgs>?)Delegate.Remove(itemRemoved, value); | ||
_itemAdded = (EventHandler<TrackingCollectionChangedEventArgs<T>>?)Delegate.Remove(_itemAdded, value); | ||
_itemRemoved = (EventHandler<TrackingCollectionChangedEventArgs<T>>?)Delegate.Remove(_itemRemoved, value); | ||
} | ||
} | ||
|
||
/// <inheritdoc/> | ||
protected override void InsertItem(int index, T item) | ||
{ | ||
base.InsertItem(index, item); | ||
itemAdded?.Invoke(this, new TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, null, index, true)); | ||
_itemAdded?.Invoke(this, new TrackingCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Add, item, default, index, true)); | ||
} | ||
|
||
/// <inheritdoc/> | ||
protected override void RemoveItem(int index) | ||
{ | ||
itemRemoved?.Invoke(this, new TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, this[index], null, index, true)); | ||
_itemRemoved?.Invoke(this, new TrackingCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Remove, this[index], default, index, true)); | ||
base.RemoveItem(index); | ||
} | ||
|
||
|
@@ -57,25 +57,25 @@ protected override void ClearItems() | |
protected void ClearItemsEvents() | ||
{ | ||
// Note: Changing CollectionChanged is not thread-safe | ||
var collectionChanged = itemRemoved; | ||
var collectionChanged = _itemRemoved; | ||
if (collectionChanged != null) | ||
{ | ||
for (var i = Count - 1; i >= 0; --i) | ||
collectionChanged(this, new TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, this[i], null, i, true)); | ||
collectionChanged(this, new TrackingCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Remove, this[i], default, i, true)); | ||
} | ||
} | ||
|
||
/// <inheritdoc/> | ||
protected override void SetItem(int index, T item) | ||
{ | ||
// Note: Changing CollectionChanged is not thread-safe | ||
var collectionChangedRemoved = itemRemoved; | ||
var collectionChangedRemoved = _itemRemoved; | ||
|
||
object? oldItem = collectionChangedRemoved != null ? this[index] : null; | ||
collectionChangedRemoved?.Invoke(this, new TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItem, null, index, false)); | ||
T? oldItem = collectionChangedRemoved != null ? this[index] : default; | ||
collectionChangedRemoved?.Invoke(this, new TrackingCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Remove, oldItem, default, index, false)); | ||
|
||
base.SetItem(index, item); | ||
|
||
itemAdded?.Invoke(this, new TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, oldItem, index, false)); | ||
_itemAdded?.Invoke(this, new TrackingCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Add, item, oldItem, index, false)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,17 @@ | ||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) | ||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. | ||
|
||
Comment on lines
-1
to
-3
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm starting to worry that you aren't feeding your IDE correctly |
||
using System.Collections.Specialized; | ||
|
||
namespace Stride.Core.Collections; | ||
|
||
public class TrackingCollectionChangedEventArgs : EventArgs | ||
public sealed class TrackingCollectionChangedEventArgs<TValue> : EventArgs | ||
{ | ||
public TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction action, object? item, object? oldItem, int index, bool collectionChanged) | ||
public TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction action, TValue? item, TValue? oldItem, int index, bool collectionChanged) | ||
{ | ||
Action = action; | ||
Item = item; | ||
OldItem = oldItem; | ||
Key = null; | ||
Index = index; | ||
CollectionChanged = collectionChanged; | ||
} | ||
|
||
public TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction action, object key, object? item, object? oldItem, bool collectionChanged) | ||
{ | ||
Action = action; | ||
Item = item; | ||
OldItem = oldItem; | ||
Key = key; | ||
Index = -1; | ||
CollectionChanged = collectionChanged; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the type of action performed. | ||
/// Allowed values are <see cref="NotifyCollectionChangedAction.Add"/> and <see cref="NotifyCollectionChangedAction.Remove"/>. | ||
|
@@ -36,15 +21,12 @@ public TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction action, | |
/// <summary> | ||
/// Gets the added or removed item (if dictionary, value only). | ||
/// </summary> | ||
public object? Item { get; } | ||
public TValue? Item { get; } | ||
|
||
/// <summary> | ||
/// Gets the previous value. Only valid if <see cref="Action"/> is <see cref="NotifyCollectionChangedAction.Add"/> and <see cref="NotifyCollectionChangedAction.Remove"/> | ||
/// </summary> | ||
public object? OldItem { get; } | ||
|
||
/// <summary>Gets the added or removed key (if dictionary).</summary> | ||
public object? Key { get; } | ||
public TValue? OldItem { get; } | ||
|
||
/// <summary> | ||
/// Gets the index in the collection (if applicable). | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,27 +18,27 @@ namespace Stride.Core.Collections; | |
/// <typeparam name="TKey">The type of the key.</typeparam> | ||
/// <typeparam name="TValue">The type of the value.</typeparam> | ||
[DataSerializer(typeof(DictionaryAllSerializer<,,>), Mode = DataSerializerGenericMode.TypeAndGenericArguments)] | ||
public class TrackingDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, ITrackingCollectionChanged | ||
public class TrackingDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, ITrackingKeyedCollectionChanged<TKey, TValue> | ||
where TKey : notnull | ||
{ | ||
private readonly Dictionary<TKey, TValue> innerDictionary; | ||
|
||
private EventHandler<TrackingCollectionChangedEventArgs>? itemAdded; | ||
private EventHandler<TrackingCollectionChangedEventArgs>? itemRemoved; | ||
private EventHandler<TrackingKeyedCollectionChangedEventArgs<TKey, TValue>>? _itemAdded; | ||
private EventHandler<TrackingKeyedCollectionChangedEventArgs<TKey, TValue>>? _itemRemoved; | ||
Comment on lines
+26
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, same here |
||
|
||
/// <inheritdoc/> | ||
public event EventHandler<TrackingCollectionChangedEventArgs> CollectionChanged | ||
public event EventHandler<TrackingKeyedCollectionChangedEventArgs<TKey, TValue>> CollectionChanged | ||
{ | ||
add | ||
{ | ||
// We keep a list in reverse order for removal, so that we can easily have multiple handlers depending on each others | ||
itemAdded = (EventHandler<TrackingCollectionChangedEventArgs>)Delegate.Combine(itemAdded, value); | ||
itemRemoved = (EventHandler<TrackingCollectionChangedEventArgs>)Delegate.Combine(value, itemRemoved); | ||
_itemAdded = (EventHandler<TrackingKeyedCollectionChangedEventArgs<TKey, TValue>>)Delegate.Combine(_itemAdded, value); | ||
_itemRemoved = (EventHandler<TrackingKeyedCollectionChangedEventArgs<TKey, TValue>>)Delegate.Combine(value, _itemRemoved); | ||
} | ||
remove | ||
{ | ||
itemAdded = (EventHandler<TrackingCollectionChangedEventArgs>?)Delegate.Remove(itemAdded, value); | ||
itemRemoved = (EventHandler<TrackingCollectionChangedEventArgs>?)Delegate.Remove(itemRemoved, value); | ||
_itemAdded = (EventHandler<TrackingKeyedCollectionChangedEventArgs<TKey, TValue>>?)Delegate.Remove(_itemAdded, value); | ||
_itemRemoved = (EventHandler<TrackingKeyedCollectionChangedEventArgs<TKey, TValue>>?)Delegate.Remove(_itemRemoved, value); | ||
} | ||
} | ||
|
||
|
@@ -54,7 +54,7 @@ public TrackingDictionary() | |
public void Add(TKey key, TValue value) | ||
{ | ||
innerDictionary.Add(key, value); | ||
itemAdded?.Invoke(this, new TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, key, value, null, true)); | ||
_itemAdded?.Invoke(this, new TrackingKeyedCollectionChangedEventArgs<TKey, TValue>(NotifyCollectionChangedAction.Add, key, value, default, true)); | ||
} | ||
|
||
/// <inheritdoc/> | ||
|
@@ -72,9 +72,9 @@ public ICollection<TKey> Keys | |
/// <inheritdoc/> | ||
public bool Remove(TKey key) | ||
{ | ||
var collectionChanged = itemRemoved; | ||
var collectionChanged = _itemRemoved; | ||
if (collectionChanged != null && innerDictionary.TryGetValue(key, out var dictValue)) | ||
collectionChanged(this, new TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, key, dictValue, null, true)); | ||
collectionChanged(this, new TrackingKeyedCollectionChangedEventArgs<TKey, TValue>(NotifyCollectionChangedAction.Remove, key, dictValue, default, true)); | ||
|
||
return innerDictionary.Remove(key); | ||
} | ||
|
@@ -100,17 +100,17 @@ public TValue this[TKey key] | |
} | ||
set | ||
{ | ||
var collectionChangedRemoved = itemRemoved; | ||
var collectionChangedRemoved = _itemRemoved; | ||
if (collectionChangedRemoved != null) | ||
{ | ||
var alreadyExisting = innerDictionary.TryGetValue(key, out var oldValue); | ||
if (alreadyExisting) | ||
collectionChangedRemoved(this, new TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, key, oldValue, null, false)); | ||
collectionChangedRemoved(this, new TrackingKeyedCollectionChangedEventArgs<TKey, TValue>(NotifyCollectionChangedAction.Remove, key, oldValue, default, false)); | ||
|
||
innerDictionary[key] = value; | ||
|
||
// Note: CollectionChanged is considered not thread-safe, so no need to skip if null here, shouldn't happen | ||
itemAdded?.Invoke(this, new TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, key, innerDictionary[key], oldValue, !alreadyExisting)); | ||
_itemAdded?.Invoke(this, new TrackingKeyedCollectionChangedEventArgs<TKey, TValue>(NotifyCollectionChangedAction.Add, key, innerDictionary[key], oldValue, !alreadyExisting)); | ||
} | ||
else | ||
{ | ||
|
@@ -128,7 +128,7 @@ public void Add(KeyValuePair<TKey, TValue> item) | |
/// <inheritdoc/> | ||
public void Clear() | ||
{ | ||
var collectionChanged = itemRemoved; | ||
var collectionChanged = _itemRemoved; | ||
if (collectionChanged != null) | ||
{ | ||
foreach (var key in innerDictionary.Keys.ToArray()) | ||
|
@@ -169,7 +169,7 @@ public bool IsReadOnly | |
/// <inheritdoc/> | ||
public bool Remove(KeyValuePair<TKey, TValue> item) | ||
{ | ||
var collectionChanged = itemRemoved; | ||
var collectionChanged = _itemRemoved; | ||
if (collectionChanged != null && innerDictionary.Contains(item)) | ||
return innerDictionary.Remove(item.Key); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,26 +12,26 @@ namespace Stride.Core.Collections; | |
/// Underlying storage is done with a <see cref="HashSet{T}"/>. | ||
/// </remarks> | ||
/// <typeparam name="T">The type of elements in the hash set.</typeparam> | ||
public class TrackingHashSet<T> : ISet<T>, IReadOnlySet<T>, ITrackingCollectionChanged | ||
public class TrackingHashSet<T> : ISet<T>, IReadOnlySet<T>, ITrackingCollectionChanged<T> | ||
{ | ||
private readonly HashSet<T> innerHashSet = []; | ||
|
||
private EventHandler<TrackingCollectionChangedEventArgs>? itemAdded; | ||
private EventHandler<TrackingCollectionChangedEventArgs>? itemRemoved; | ||
private EventHandler<TrackingCollectionChangedEventArgs<T>>? _itemAdded; | ||
private EventHandler<TrackingCollectionChangedEventArgs<T>>? _itemRemoved; | ||
Comment on lines
+19
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup |
||
|
||
/// <inheritdoc/> | ||
public event EventHandler<TrackingCollectionChangedEventArgs> CollectionChanged | ||
public event EventHandler<TrackingCollectionChangedEventArgs<T>> CollectionChanged | ||
{ | ||
add | ||
{ | ||
// We keep a list in reverse order for removal, so that we can easily have multiple handlers depending on each others | ||
itemAdded = (EventHandler<TrackingCollectionChangedEventArgs>)Delegate.Combine(itemAdded, value); | ||
itemRemoved = (EventHandler<TrackingCollectionChangedEventArgs>)Delegate.Combine(value, itemRemoved); | ||
_itemAdded = (EventHandler<TrackingCollectionChangedEventArgs<T>>)Delegate.Combine(_itemAdded, value); | ||
_itemRemoved = (EventHandler<TrackingCollectionChangedEventArgs<T>>)Delegate.Combine(value, _itemRemoved); | ||
} | ||
remove | ||
{ | ||
itemAdded = (EventHandler<TrackingCollectionChangedEventArgs>?)Delegate.Remove(itemAdded, value); | ||
itemRemoved = (EventHandler<TrackingCollectionChangedEventArgs>?)Delegate.Remove(itemRemoved, value); | ||
_itemAdded = (EventHandler<TrackingCollectionChangedEventArgs<T>>?)Delegate.Remove(_itemAdded, value); | ||
_itemRemoved = (EventHandler<TrackingCollectionChangedEventArgs<T>>?)Delegate.Remove(_itemRemoved, value); | ||
} | ||
} | ||
|
||
|
@@ -40,7 +40,7 @@ public bool Add(T item) | |
{ | ||
if (innerHashSet.Add(item)) | ||
{ | ||
itemAdded?.Invoke(this, new TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, null, -1, true)); | ||
_itemAdded?.Invoke(this, new TrackingCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Add, item, default, -1, true)); | ||
return true; | ||
} | ||
|
||
|
@@ -116,7 +116,7 @@ void ICollection<T>.Add(T item) | |
/// <inheritdoc/> | ||
public void Clear() | ||
{ | ||
if (itemRemoved != null) | ||
if (_itemRemoved != null) | ||
{ | ||
foreach (var item in innerHashSet.ToArray()) | ||
{ | ||
|
@@ -153,7 +153,7 @@ public bool Remove(T item) | |
if (!innerHashSet.Remove(item)) | ||
return false; | ||
|
||
itemRemoved?.Invoke(this, new TrackingCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, null, -1, true)); | ||
_itemRemoved?.Invoke(this, new TrackingCollectionChangedEventArgs<T>(NotifyCollectionChangedAction.Remove, item, default, -1, true)); | ||
return true; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) | ||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. | ||
|
||
using System.Collections.Specialized; | ||
|
||
namespace Stride.Core.Collections; | ||
|
||
public sealed class TrackingKeyedCollectionChangedEventArgs<TKey, TValue> : EventArgs | ||
{ | ||
public TrackingKeyedCollectionChangedEventArgs(NotifyCollectionChangedAction action, TKey key, TValue? item, TValue? oldItem, bool collectionChanged) | ||
{ | ||
Action = action; | ||
Item = item; | ||
OldItem = oldItem; | ||
Key = key; | ||
Index = -1; | ||
CollectionChanged = collectionChanged; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the type of action performed. | ||
/// Allowed values are <see cref="NotifyCollectionChangedAction.Add"/> and <see cref="NotifyCollectionChangedAction.Remove"/>. | ||
/// </summary> | ||
public NotifyCollectionChangedAction Action { get; } | ||
|
||
/// <summary> | ||
/// Gets the added or removed item (if dictionary, value only). | ||
/// </summary> | ||
public TValue? Item { get; } | ||
|
||
/// <summary> | ||
/// Gets the previous value. Only valid if <see cref="Action"/> is <see cref="NotifyCollectionChangedAction.Add"/> and <see cref="NotifyCollectionChangedAction.Remove"/> | ||
/// </summary> | ||
public TValue? OldItem { get; } | ||
|
||
/// <summary>Gets the added or removed key (if dictionary).</summary> | ||
public TKey Key { get; } | ||
|
||
/// <summary> | ||
/// Gets the index in the collection (if applicable). | ||
/// </summary> | ||
public int Index { get; } | ||
|
||
/// <summary> | ||
/// Gets a value indicating whether [collection changed (not a replacement but real insertion/removal)]. | ||
/// </summary> | ||
/// <value> | ||
/// <c>true</c> if [collection changed]; otherwise, <c>false</c>. | ||
/// </value> | ||
public bool CollectionChanged { get; } | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like your IDE ate the header