Skip to content

Commit

Permalink
dotnet#110161 Allow collection expressions for 'System.Collections.Ob…
Browse files Browse the repository at this point in the history
…jectModel' collection types

dotnet#110161
  • Loading branch information
AlexRadch committed Jan 5, 2025
1 parent fb7fe3e commit 74f8733
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Linq;
using Xunit;

namespace System.Collections.ObjectModel.Tests
Expand All @@ -21,6 +22,24 @@ public void Ctor_SetProperty_Roundtrips()
Assert.Same(set, new DerivedReadOnlySet<int>(set).Set);
}

[Fact]
public static void Ctor_CollectionExpressions_Empty()
{
ReadOnlySet<int> set = [];
Assert.IsType<ReadOnlySet<int>>(set);
Assert.Empty(set);
Assert.Same(set, ReadOnlySet<int>.Empty);
}

[Fact]
public static void Ctor_CollectionExpressions()
{
int[] array = [1, 2, 3, 3, 2, 1];
ReadOnlySet<int> set = [.. array];
Assert.IsType<ReadOnlySet<int>>(set);
Assert.Equal(set.Order(), array.Distinct().Order());
}

[Fact]
public void Empty_EmptyAndIdempotent()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace System.Collections.ObjectModel
{
[Serializable]
[CollectionBuilder(typeof(ReadOnlyCollection), "CreateCollection")]
[DebuggerTypeProxy(typeof(ICollectionDebugView<>))]
[DebuggerDisplay("Count = {Count}")]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
Expand Down Expand Up @@ -229,4 +231,35 @@ void IList.RemoveAt(int index)
ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
}
}

public static class ReadOnlyCollection
{
/// <summary>
/// Creates a new <see cref="ReadOnlyCollection{T}"/> from the specified span of values.
/// This method (simplifies collection initialization)[/dotnet/csharp/language-reference/operators/collection-expressions]
/// to create a new <see cref="ReadOnlyCollection{T}"/> with the specified values.
/// </summary>
/// <typeparam name="T">The type of elements in the collection.</typeparam>
/// <param name="values">The span of values to include in the collection.</param>
/// <returns>A new <see cref="ReadOnlyCollection{T}"/> containing the specified values.</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
#pragma warning disable IDE0301 // Simplify collection initialization
public static ReadOnlyCollection<T> CreateCollection<T>(params ReadOnlySpan<T> values) =>
values.Length <= 0 ? ReadOnlyCollection<T>.Empty : new ReadOnlyCollection<T>(values.ToArray());
#pragma warning restore IDE0301 // Simplify collection initialization

/// <summary>
/// Creates a new <see cref="ReadOnlySet{T}"/> from the specified span of values.
/// This method (simplifies collection initialization)[/dotnet/csharp/language-reference/operators/collection-expressions]
/// to create a new <see cref="ReadOnlySet{T}"/> with the specified values.
/// </summary>
/// <typeparam name="T">The type of elements in the collection.</typeparam>
/// <param name="values">The span of values to include in the collection.</param>
/// <returns>A new <see cref="ReadOnlySet{T}"/> containing the specified values.</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
#pragma warning disable IDE0301 // Simplify collection initialization
public static ReadOnlySet<T> CreateSet<T>(params ReadOnlySpan<T> values) =>
values.Length <= 0 ? ReadOnlySet<T>.Empty : new ReadOnlySet<T>((HashSet<T>)[.. values]);
#pragma warning restore IDE0301 // Simplify collection initialization
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@

using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace System.Collections.ObjectModel
{
/// <summary>Represents a read-only, generic set of values.</summary>
/// <typeparam name="T">The type of values in the set.</typeparam>
[CollectionBuilder(typeof(ReadOnlyCollection), "CreateSet")]
[DebuggerDisplay("Count = {Count}")]
public class ReadOnlySet<T> : IReadOnlySet<T>, ISet<T>, ICollection
{
Expand Down
9 changes: 9 additions & 0 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8366,6 +8366,14 @@ void System.Collections.ICollection.CopyTo(System.Array array, int index) { }
void System.Collections.IList.Insert(int index, object? value) { }
void System.Collections.IList.Remove(object? value) { }
}
public static partial class ReadOnlyCollection
{
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static System.Collections.ObjectModel.ReadOnlyCollection<T> CreateCollection<T>(params System.ReadOnlySpan<T> values) { throw null; }
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public static System.Collections.ObjectModel.ReadOnlySet<T> CreateSet<T>(params System.ReadOnlySpan<T> values) { throw null; }
}
[System.Runtime.CompilerServices.CollectionBuilder(typeof(System.Collections.ObjectModel.ReadOnlyCollection), "CreateCollection")]
public partial class ReadOnlyCollection<T> : System.Collections.Generic.ICollection<T>, System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.IReadOnlyList<T>, System.Collections.ICollection, System.Collections.IEnumerable, System.Collections.IList
{
public ReadOnlyCollection(System.Collections.Generic.IList<T> list) { }
Expand Down Expand Up @@ -8471,6 +8479,7 @@ void System.Collections.ICollection.CopyTo(System.Array array, int index) { }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
}
}
[System.Runtime.CompilerServices.CollectionBuilder(typeof(System.Collections.ObjectModel.ReadOnlyCollection), "CreateSet")]
public partial class ReadOnlySet<T> : System.Collections.Generic.ICollection<T>, System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.IReadOnlySet<T>, System.Collections.Generic.ISet<T>, System.Collections.ICollection, System.Collections.IEnumerable
{
public ReadOnlySet(System.Collections.Generic.ISet<T> @set) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,23 @@ public static void Ctor_IList()
Assert.Same(s_intArray, collection.GetItems());
}

[Fact]
public static void Ctor_CollectionExpressions_Empty()
{
ReadOnlyCollection<int> c = [];
Assert.IsType<ReadOnlyCollection<int>>(c);
Assert.Empty(c);
Assert.Same(c, ReadOnlyCollection<int>.Empty);
}

[Fact]
public static void Ctor_CollectionExpressions()
{
ReadOnlyCollection<int> c = [.. s_intArray];
Assert.IsType<ReadOnlyCollection<int>>(c);
Assert.Equal(c, s_intArray);
}

[Fact]
public static void Count()
{
Expand Down

0 comments on commit 74f8733

Please sign in to comment.