diff --git a/src/libraries/Common/src/System/Diagnostics/DiagnosticsHelper.cs b/src/libraries/Common/src/System/Diagnostics/DiagnosticsHelper.cs index ce7f345b0ea9c..dcc9de3e4ad65 100644 --- a/src/libraries/Common/src/System/Diagnostics/DiagnosticsHelper.cs +++ b/src/libraries/Common/src/System/Diagnostics/DiagnosticsHelper.cs @@ -35,14 +35,22 @@ internal static bool CompareTags(List>? sortedTags int size = count / (sizeof(ulong) * 8) + 1; BitMapper bitMapper = new BitMapper(size <= 100 ? stackalloc ulong[size] : new ulong[size]); +#if NET9_0_OR_GREATER // ICollection : IReadOnlyCollection on .NET 9+ + if (tags2 is IReadOnlyCollection> tagsCol) +#else if (tags2 is ICollection> tagsCol) +#endif { if (tagsCol.Count != count) { return false; } +#if NET9_0_OR_GREATER // IList : IReadOnlyList on .NET 9+ + if (tagsCol is IReadOnlyList> secondList) +#else if (tagsCol is IList> secondList) +#endif { for (int i = 0; i < count; i++) { diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSetInternalBase.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSetInternalBase.cs index 4afe1f7503e75..02e5e0cc07cb2 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSetInternalBase.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenSetInternalBase.cs @@ -32,7 +32,11 @@ private protected override bool IsProperSubsetOfCore(IEnumerable other) { Debug.Assert(_thisSet.Count != 0, "EmptyFrozenSet should have been used."); +#if NET9_0_OR_GREATER // ICollection : IReadOnlyCollection on .NET 9+ + if (other is IReadOnlyCollection otherAsCollection) +#else if (other is ICollection otherAsCollection) +#endif { int otherCount = otherAsCollection.Count; @@ -59,7 +63,11 @@ private protected override bool IsProperSupersetOfCore(IEnumerable other) { Debug.Assert(_thisSet.Count != 0, "EmptyFrozenSet should have been used."); +#if NET9_0_OR_GREATER // ICollection : IReadOnlyCollection on .NET 9+ + if (other is IReadOnlyCollection otherAsCollection) +#else if (other is ICollection otherAsCollection) +#endif { int otherCount = otherAsCollection.Count; @@ -103,7 +111,11 @@ private protected override bool IsSupersetOfCore(IEnumerable other) Debug.Assert(_thisSet.Count != 0, "EmptyFrozenSet should have been used."); // Try to compute the answer based purely on counts. +#if NET9_0_OR_GREATER // ICollection : IReadOnlyCollection on .NET 9+ + if (other is IReadOnlyCollection otherAsCollection) +#else if (other is ICollection otherAsCollection) +#endif { int otherCount = otherAsCollection.Count; diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs index 66b365bad872b..dc9c7d26898b7 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableExtensions.Minimal.cs @@ -38,11 +38,13 @@ internal static bool TryGetCount(this IEnumerable sequence, out int count) return true; } +#if !NET9_0_OR_GREATER // ICollection : IReadOnlyCollection on .NET 9+ if (sequence is ICollection collectionOfT) { count = collectionOfT.Count; return true; } +#endif if (sequence is IReadOnlyCollection readOnlyCollection) { diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs b/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs index 5047b76433738..072e5ac34d605 100644 --- a/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs +++ b/src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs @@ -462,7 +462,7 @@ public void EnqueueRange(IEnumerable elements, TPriority priority) ArgumentNullException.ThrowIfNull(elements); int count; - if (elements is ICollection collection && + if (elements is IReadOnlyCollection collection && (count = collection.Count) > _nodes.Length - _size) { Grow(checked(_size + count)); diff --git a/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs b/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs index 2f7406d0d7bf4..fd0beccb28a77 100644 --- a/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs +++ b/src/libraries/System.Collections/src/System/Collections/Generic/SortedSet.cs @@ -1323,7 +1323,7 @@ public bool Overlaps(IEnumerable other) if (Count == 0) return false; - if (other is ICollection c && c.Count == 0) + if (other is IReadOnlyCollection c && c.Count == 0) return false; SortedSet? asSorted = other as SortedSet; diff --git a/src/libraries/System.Linq.Expressions/src/System/Dynamic/ExpandoObject.cs b/src/libraries/System.Linq.Expressions/src/System/Dynamic/ExpandoObject.cs index 288d01c185dbf..906ee3fd84fc2 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Dynamic/ExpandoObject.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Dynamic/ExpandoObject.cs @@ -17,7 +17,7 @@ namespace System.Dynamic /// /// Represents an object with members that can be dynamically added and removed at runtime. /// - public sealed class ExpandoObject : IDynamicMetaObjectProvider, IDictionary, INotifyPropertyChanged + public sealed class ExpandoObject : IDynamicMetaObjectProvider, IDictionary, IReadOnlyDictionary, INotifyPropertyChanged { private static readonly MethodInfo s_expandoTryGetValue = typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.ExpandoTryGetValue))!; @@ -618,6 +618,10 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() ICollection IDictionary.Values => new ValueCollection(this); + IEnumerable IReadOnlyDictionary.Keys => new KeyCollection(this); + + IEnumerable IReadOnlyDictionary.Values => new ValueCollection(this); + object? IDictionary.this[string key] { get @@ -636,6 +640,18 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() } } + object? IReadOnlyDictionary.this[string key] + { + get + { + if (!TryGetValueForKey(key, out object? value)) + { + throw System.Linq.Expressions.Error.KeyDoesNotExistInExpando(key); + } + return value; + } + } + void IDictionary.Add(string key, object? value) { this.TryAddMember(key, value); @@ -650,6 +666,15 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() return index >= 0 && data[index] != Uninitialized; } + bool IReadOnlyDictionary.ContainsKey(string key) + { + ArgumentNullException.ThrowIfNull(key); + + ExpandoData data = _data; + int index = data.Class.GetValueIndexCaseSensitive(key); + return index >= 0 && data[index] != Uninitialized; + } + bool IDictionary.Remove(string key) { ArgumentNullException.ThrowIfNull(key); @@ -662,6 +687,11 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() return TryGetValueForKey(key, out value); } + bool IReadOnlyDictionary.TryGetValue(string key, out object? value) + { + return TryGetValueForKey(key, out value); + } + #endregion #region ICollection> Members diff --git a/src/libraries/System.Linq.Parallel/src/System/Linq/ParallelEnumerable.cs b/src/libraries/System.Linq.Parallel/src/System/Linq/ParallelEnumerable.cs index 55ef371ea0422..f0885d3d3e7d4 100644 --- a/src/libraries/System.Linq.Parallel/src/System/Linq/ParallelEnumerable.cs +++ b/src/libraries/System.Linq.Parallel/src/System/Linq/ParallelEnumerable.cs @@ -1852,7 +1852,7 @@ public static int Count(this ParallelQuery source) // If the data source is a collection, we can just return the count right away. if (source is ParallelEnumerableWrapper sourceAsWrapper) { - if (sourceAsWrapper.WrappedEnumerable is ICollection sourceAsCollection) + if (sourceAsWrapper.WrappedEnumerable is IReadOnlyCollection sourceAsCollection) { return sourceAsCollection.Count; } @@ -1923,7 +1923,7 @@ public static long LongCount(this ParallelQuery source) // If the data source is a collection, we can just return the count right away. if (source is ParallelEnumerableWrapper sourceAsWrapper) { - if (sourceAsWrapper.WrappedEnumerable is ICollection sourceAsCollection) + if (sourceAsWrapper.WrappedEnumerable is IReadOnlyCollection sourceAsCollection) { return sourceAsCollection.Count; } diff --git a/src/libraries/System.Linq/src/System/Linq/AnyAll.cs b/src/libraries/System.Linq/src/System/Linq/AnyAll.cs index 28a3783aa8829..d6d6e4adccdeb 100644 --- a/src/libraries/System.Linq/src/System/Linq/AnyAll.cs +++ b/src/libraries/System.Linq/src/System/Linq/AnyAll.cs @@ -15,7 +15,7 @@ public static bool Any(this IEnumerable source) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if (source is ICollection gc) + if (source is IReadOnlyCollection gc) { return gc.Count != 0; } diff --git a/src/libraries/System.Linq/src/System/Linq/AppendPrepend.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/AppendPrepend.SpeedOpt.cs index 01adb0af01e45..cd6fb6fa171ad 100644 --- a/src/libraries/System.Linq/src/System/Linq/AppendPrepend.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/AppendPrepend.SpeedOpt.cs @@ -127,7 +127,7 @@ public override int GetCount(bool onlyIfCheap) return count == -1 ? -1 : count + 1; } - return !onlyIfCheap || _source is ICollection ? _source.Count() + 1 : -1; + return !onlyIfCheap || _source is IReadOnlyCollection ? _source.Count() + 1 : -1; } public override TSource? TryGetFirst(out bool found) @@ -276,7 +276,7 @@ public override int GetCount(bool onlyIfCheap) return count == -1 ? -1 : count + _appendCount + _prependCount; } - return !onlyIfCheap || _source is ICollection ? _source.Count() + _appendCount + _prependCount : -1; + return !onlyIfCheap || _source is IReadOnlyCollection ? _source.Count() + _appendCount + _prependCount : -1; } } } diff --git a/src/libraries/System.Linq/src/System/Linq/Count.cs b/src/libraries/System.Linq/src/System/Linq/Count.cs index 6b8819f8c3cbc..9b2511e0563c5 100644 --- a/src/libraries/System.Linq/src/System/Linq/Count.cs +++ b/src/libraries/System.Linq/src/System/Linq/Count.cs @@ -15,7 +15,7 @@ public static int Count(this IEnumerable source) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if (source is ICollection collectionoft) + if (source is IReadOnlyCollection collectionoft) { return collectionoft.Count; } @@ -101,7 +101,7 @@ public static bool TryGetNonEnumeratedCount(this IEnumerable s ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if (source is ICollection collectionoft) + if (source is IReadOnlyCollection collectionoft) { count = collectionoft.Count; return true; diff --git a/src/libraries/System.Linq/src/System/Linq/DefaultIfEmpty.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/DefaultIfEmpty.SpeedOpt.cs index c89d6797581e9..45f673f73486a 100644 --- a/src/libraries/System.Linq/src/System/Linq/DefaultIfEmpty.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/DefaultIfEmpty.SpeedOpt.cs @@ -30,7 +30,7 @@ public override List ToList() public override int GetCount(bool onlyIfCheap) { int count; - if (!onlyIfCheap || _source is ICollection || _source is ICollection) + if (!onlyIfCheap || _source is IReadOnlyCollection || _source is ICollection) { count = _source.Count(); } diff --git a/src/libraries/System.Linq/src/System/Linq/ElementAt.cs b/src/libraries/System.Linq/src/System/Linq/ElementAt.cs index 97b87f9eba999..824a152a7764c 100644 --- a/src/libraries/System.Linq/src/System/Linq/ElementAt.cs +++ b/src/libraries/System.Linq/src/System/Linq/ElementAt.cs @@ -16,7 +16,7 @@ public static TSource ElementAt(this IEnumerable source, int i ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if (source is IList list) + if (source is IReadOnlyList list) { return list[index]; } @@ -115,7 +115,7 @@ public static TSource ElementAt(this IEnumerable source, Index private static TSource? TryGetElementAt(this IEnumerable source, int index, out bool found) { - if (source is IList list) + if (source is IReadOnlyList list) { return (found = (uint)index < (uint)list.Count) ? list[index] : diff --git a/src/libraries/System.Linq/src/System/Linq/First.cs b/src/libraries/System.Linq/src/System/Linq/First.cs index 74ff81c2fec83..22532cdb18d13 100644 --- a/src/libraries/System.Linq/src/System/Linq/First.cs +++ b/src/libraries/System.Linq/src/System/Linq/First.cs @@ -78,7 +78,7 @@ public static TSource FirstOrDefault(this IEnumerable source, private static TSource? TryGetFirstNonIterator(IEnumerable source, out bool found) { - if (source is IList list) + if (source is IReadOnlyList list) { if (list.Count > 0) { diff --git a/src/libraries/System.Linq/src/System/Linq/Grouping.cs b/src/libraries/System.Linq/src/System/Linq/Grouping.cs index 6e19e4ab384e4..47be36572acad 100644 --- a/src/libraries/System.Linq/src/System/Linq/Grouping.cs +++ b/src/libraries/System.Linq/src/System/Linq/Grouping.cs @@ -351,7 +351,7 @@ public interface IGrouping : IEnumerable [DebuggerDisplay("Key = {Key}")] [DebuggerTypeProxy(typeof(SystemLinq_GroupingDebugView<,>))] - internal sealed class Grouping : IGrouping, IList + internal sealed class Grouping : IGrouping, IList, IReadOnlyList { internal readonly TKey _key; internal readonly int _hashCode; @@ -398,6 +398,8 @@ public IEnumerator GetEnumerator() int ICollection.Count => _count; + int IReadOnlyCollection.Count => _count; + bool ICollection.IsReadOnly => true; void ICollection.Add(TElement item) => ThrowHelper.ThrowNotSupportedException(); @@ -431,5 +433,18 @@ TElement IList.this[int index] set => ThrowHelper.ThrowNotSupportedException(); } + + TElement IReadOnlyList.this[int index] + { + get + { + if ((uint)index >= (uint)_count) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index); + } + + return _elements[index]; + } + } } } diff --git a/src/libraries/System.Linq/src/System/Linq/Last.cs b/src/libraries/System.Linq/src/System/Linq/Last.cs index 007ee1659c3f5..e17e409e25e3f 100644 --- a/src/libraries/System.Linq/src/System/Linq/Last.cs +++ b/src/libraries/System.Linq/src/System/Linq/Last.cs @@ -77,7 +77,7 @@ public static TSource LastOrDefault(this IEnumerable source, F private static TSource? TryGetLastNonIterator(IEnumerable source, out bool found) { - if (source is IList list) + if (source is IReadOnlyList list) { int count = list.Count; if (count > 0) @@ -126,7 +126,7 @@ public static TSource LastOrDefault(this IEnumerable source, F return ordered.TryGetLast(predicate, out found); } - if (source is IList list) + if (source is IReadOnlyList list) { for (int i = list.Count - 1; i >= 0; --i) { diff --git a/src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.SpeedOpt.cs index bf65a34b06efa..ac9225303b426 100644 --- a/src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.SpeedOpt.cs @@ -58,7 +58,7 @@ public override int GetCount(bool onlyIfCheap) return iterator.GetCount(onlyIfCheap); } - return !onlyIfCheap || _source is ICollection || _source is ICollection ? _source.Count() : -1; + return !onlyIfCheap || _source is IReadOnlyCollection || _source is ICollection ? _source.Count() : -1; } internal TElement[] ToArray(int minIdx, int maxIdx) diff --git a/src/libraries/System.Linq/src/System/Linq/Reverse.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/Reverse.SpeedOpt.cs index d1ec26de879af..168ca818c9611 100644 --- a/src/libraries/System.Linq/src/System/Linq/Reverse.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/Reverse.SpeedOpt.cs @@ -30,7 +30,7 @@ public override int GetCount(bool onlyIfCheap) => public override TSource? TryGetElementAt(int index, out bool found) { - if (_source is IList list) + if (_source is IReadOnlyList list) { int count = list.Count; if ((uint)index < (uint)count) @@ -59,7 +59,7 @@ public override int GetCount(bool onlyIfCheap) => { return iterator.TryGetLast(out found); } - else if (_source is IList list) + else if (_source is IReadOnlyList list) { int count = list.Count; if (count > 0) @@ -95,7 +95,7 @@ public override int GetCount(bool onlyIfCheap) => { return iterator.TryGetFirst(out found); } - else if (_source is IList list) + else if (_source is IReadOnlyList list) { if (list.Count > 0) { diff --git a/src/libraries/System.Linq/src/System/Linq/SequenceEqual.cs b/src/libraries/System.Linq/src/System/Linq/SequenceEqual.cs index 16bf60e686145..2568721f1ce16 100644 --- a/src/libraries/System.Linq/src/System/Linq/SequenceEqual.cs +++ b/src/libraries/System.Linq/src/System/Linq/SequenceEqual.cs @@ -22,7 +22,7 @@ public static bool SequenceEqual(this IEnumerable first, IEnum ThrowHelper.ThrowArgumentNullException(ExceptionArgument.second); } - if (first is ICollection firstCol && second is ICollection secondCol) + if (first is IReadOnlyCollection firstCol && second is IReadOnlyCollection secondCol) { if (first.TryGetSpan(out ReadOnlySpan firstSpan) && second.TryGetSpan(out ReadOnlySpan secondSpan)) { @@ -34,7 +34,7 @@ public static bool SequenceEqual(this IEnumerable first, IEnum return false; } - if (firstCol is IList firstList && secondCol is IList secondList) + if (firstCol is IReadOnlyList firstList && secondCol is IReadOnlyList secondList) { comparer ??= EqualityComparer.Default; diff --git a/src/libraries/System.Linq/src/System/Linq/Single.cs b/src/libraries/System.Linq/src/System/Linq/Single.cs index 9c7328cc3ff16..78e548e680669 100644 --- a/src/libraries/System.Linq/src/System/Linq/Single.cs +++ b/src/libraries/System.Linq/src/System/Linq/Single.cs @@ -69,7 +69,7 @@ public static TSource SingleOrDefault(this IEnumerable source, ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if (source is IList list) + if (source is IReadOnlyList list) { switch (list.Count) { diff --git a/src/libraries/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ServiceNameCollection.cs b/src/libraries/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ServiceNameCollection.cs index 532f6e950d6b0..4abe58873916a 100644 --- a/src/libraries/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ServiceNameCollection.cs +++ b/src/libraries/System.Net.Security/src/System/Security/Authentication/ExtendedProtection/ServiceNameCollection.cs @@ -147,7 +147,7 @@ private void AddIfNew(string serviceName) /// private static int GetCountOrOne(IEnumerable collection) { - ICollection? c = collection as ICollection; + IReadOnlyCollection? c = collection as IReadOnlyCollection; return c != null ? c.Count : 1; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs index bfa9fcf65469e..2eff1c59b12ec 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs @@ -89,7 +89,7 @@ public ConcurrentQueue(IEnumerable collection) // case we round its length up to a power of 2, as all segments must // be a power of 2 in length. int length = InitialSegmentLength; - if (collection is ICollection c) + if (collection is IReadOnlyCollection c) { int count = c.Count; if (count > length) diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs index 9b18d4a125ed2..f20e3c5cfee21 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs @@ -98,7 +98,7 @@ public Dictionary(IDictionary dictionary, IEqualityComparer? public Dictionary(IEnumerable> collection) : this(collection, null) { } public Dictionary(IEnumerable> collection, IEqualityComparer? comparer) : - this((collection as ICollection>)?.Count ?? 0, comparer) + this((collection as IReadOnlyCollection>)?.Count ?? 0, comparer) { if (collection == null) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs index 3b86548d20a7e..6467164d6becb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs @@ -99,7 +99,7 @@ public HashSet(IEnumerable collection, IEqualityComparer? comparer) : this { // To avoid excess resizes, first set size based on collection's count. The collection may // contain duplicates, so call TrimExcess if resulting HashSet is larger than the threshold. - if (collection is ICollection coll) + if (collection is IReadOnlyCollection coll) { int count = coll.Count; if (count > 0) @@ -513,7 +513,7 @@ public void IntersectWith(IEnumerable other) } // If other is known to be empty, intersection is empty set; remove all elements, and we're done. - if (other is ICollection otherAsCollection) + if (other is IReadOnlyCollection otherAsCollection) { if (otherAsCollection.Count == 0) { @@ -652,7 +652,7 @@ public bool IsProperSubsetOf(IEnumerable other) return false; } - if (other is ICollection otherAsCollection) + if (other is IReadOnlyCollection otherAsCollection) { // No set is a proper subset of an empty set. if (otherAsCollection.Count == 0) @@ -701,7 +701,7 @@ public bool IsSupersetOf(IEnumerable other) } // Try to fall out early based on counts. - if (other is ICollection otherAsCollection) + if (other is IReadOnlyCollection otherAsCollection) { // If other is the empty set then this is a superset. if (otherAsCollection.Count == 0) @@ -745,7 +745,7 @@ public bool IsProperSupersetOf(IEnumerable other) return false; } - if (other is ICollection otherAsCollection) + if (other is IReadOnlyCollection otherAsCollection) { // If other is the empty set then this is a superset. if (otherAsCollection.Count == 0) @@ -838,7 +838,7 @@ public bool SetEquals(IEnumerable other) { // If this count is 0 but other contains at least one element, they can't be equal. if (Count == 0 && - other is ICollection otherAsCollection && + other is IReadOnlyCollection otherAsCollection && otherAsCollection.Count > 0) { return false; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQuerySequence.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQuerySequence.cs index 3c7e5b6ad25c3..23fc7a5c2e65a 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQuerySequence.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQuerySequence.cs @@ -19,7 +19,7 @@ namespace System.Xml.Xsl.Runtime /// A sequence of Xml values that dynamically expands and allows random access to items. /// [EditorBrowsable(EditorBrowsableState.Never)] - public class XmlQuerySequence : IList, System.Collections.IList + public class XmlQuerySequence : IList, IReadOnlyList, System.Collections.IList { public static readonly XmlQuerySequence Empty = new XmlQuerySequence(); @@ -489,7 +489,7 @@ public void AddClone(XPathItem item) /// A sequence of Xml nodes that dynamically expands and allows random access to items. /// [EditorBrowsable(EditorBrowsableState.Never)] - public sealed class XmlQueryNodeSequence : XmlQuerySequence, IList + public sealed class XmlQueryNodeSequence : XmlQuerySequence, IList, IReadOnlyList { public static new readonly XmlQueryNodeSequence Empty = new XmlQueryNodeSequence(); @@ -731,6 +731,19 @@ XPathItem IList.this[int index] set { throw new NotSupportedException(); } } + /// + /// Return item at the specified index. + /// + XPathItem IReadOnlyList.this[int index] + { + get + { + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count); + + return base[index]; + } + } + /// /// Returns the index of the specified value in the sequence. /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs index 24f8653053af7..021a4ac75b3c7 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs @@ -35,7 +35,12 @@ public JsonObject(IEnumerable> properties, JsonN { bool isCaseInsensitive = IsCaseInsensitive(options); - JsonPropertyDictionary dictionary = properties is ICollection> propertiesCollection + JsonPropertyDictionary dictionary = +#if NET9_0_OR_GREATER // ICollection : IReadOnlyCollection on .NET 9+ + properties is IReadOnlyCollection> propertiesCollection +#else + properties is ICollection> propertiesCollection +#endif ? new(isCaseInsensitive, propertiesCollection.Count) : new(isCaseInsensitive);