-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
[API Proposal]: Expose Version on List<T> and similar Enumerables #86795
Comments
Tagging subscribers to this area: @dotnet/area-system-collections Issue DetailsBackground and motivationThe internal implementation of List, HashSet and others all contain a _version field. This is then used to send out CollectionModifiedExceptions during Enumerations. It would be awesome if these versions would be available as a public property. Reasons why this is useful:
As far as costs go, this one feels pretty free, given that it's already implemented on most enumerables within System.Collections.Generic. That said, I understand there's a cost of maintenance for any API surface. Potential candidates for this change would include: List API Proposalnamespace System.Collections.Generic;
public class List<T> : IEnumerable<T>, [...]
{
....
///<summary>
/// A number indicating the current version of the data structure. Increments when the collection is modified.
/// Not guaranteed to be sequential.
///</summary>
public int Version => _version;
...
} API UsageI wanna know if the list I passed into a method was modified var myStuff = new List<Valuables>(10,000);
var oldVersion = myStuff.Version;
var value = otherObj.Appraise(myStuff);
if(oldVersion != myStuff.Version){
// complicated iteration over long list
} I wanna poll the list to see if it's changed since I last touched it. public class Party {
public List<Person> Invitees { get; set; }
private int _version;
public void OnIdCheck(){
if(_version == Invitees.Version) return;
// complicated iteration over long list
}
} I wanna implement my own funky iterator that throws its own CollectionModifiedException. public struct PrimeNumberListEnumerator<T> : IEnumerator<T> {
...
public PrimeNumberListEnumerator() {
_list = list;
_index = 0;
_version = list.Version; // !!!
_current = default;
}
public bool MoveNext() {
if (_version != _list._version) {
ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion();
}
int primeIndex = CachedPrimeSieve.GetPrime(_index);
if ((uint)primeIndex < (uint)_list.Count)
{
_current = _list[primeIndex];
_index++;
return true;
}
_index = _list._size + 1;
_current = default;
return false;
}
....
} Alternative DesignsThere's currently an ObservableCollection that has the ability to be used for observing collection changes, but its API is push-based. This allows for a polling or pull-based api without requiring a buncha OnNotificationChanged listeners. Furthermore, this allows the caller to A lot of use-cases could be circumvented with careful use of IReadOnlyList and separating input and output lists. The downsides of this is Allocating and Copying. All my homies hate Allocating and Copying. Also, there are 3rd party APIs that are unchangeable that use List as an input and are not possible to change. Risks
|
See #81523 , where the proposal is to remove the version checks. Part of the problem with this is that the modification exception isn't guaranteed to be thrown, because the version isn't always incremented. If we exposed this, we would have to make that behavior guaranteed. |
I think using either If a third-party library is mutating your lists unexpectedly, then it's a bad library. |
Given #81523 I don't think we would ever consider doing this. |
Background and motivation
The internal implementation of
List
,HashSet
and others all contain a_version
field.This is then used to send out
CollectionModifiedException
during Enumerations.It would be awesome if these versions would be available as a public property.
Reasons why this is useful:
CollectionModifiedException
As far as costs go, this one feels pretty free, given that it's already implemented on most enumerables within
System.Collections.Generic
. That said, I understand there's a cost of maintenance for any API surface.Potential candidates for this change would include:
List<T>
HashSet<T>
Queue<T>
Dictionary<T>
perhaps also the non-generic ones.
API Proposal
API Usage
I wanna know if the list I passed into a method was modified
I wanna poll the list to see if it's changed since I last touched it.
I wanna implement my own funky iterator that throws its own CollectionModifiedException.
Alternative Designs
There's currently an ObservableCollection that has the ability to be used for observing collection changes, but its API is push-based. This Version based approach allows for a polling or pull-based api without requiring a buncha OnNotificationChanged listeners. Furthermore, this allows the caller to determine the time of reaction to the change.
A lot of use-cases could be circumvented with careful use of IReadOnlyList and separating input and output lists. The downsides of this is Allocating and Copying. All my homies hate Allocating and Copying. Also, there are 3rd party APIs that are shipped that use List as an input and are not possible to change.
Risks
Some runtimes may use other arcane methods for detecting modification of such structures (memhash?), and are not guaranteed to have _version alredy implemented.
This number could overflow. Currently it's implemented as an Int everywhere, but not possible to change due binary serialization.
The text was updated successfully, but these errors were encountered: