Skip to content

[API Proposal]: ReadOnlySet<T> #100113

@stephentoub

Description

@stephentoub

Background and motivation

If someone wants to return an IList<T> via a read-only wrapper that prevents the list from being mutated via that reference, they can wrap it in a ReadOnlyCollection<T>.

If they have an IDictionary<TKey, TValue>, they can wrap it in a ReadOnlyDictionary<TKey, TValue>.

But if they have an ISet<T>, there's no ReadOnlySet<T> that can be used to easily wrap the set. The dev needs to either write their own wrapper type, and will instead often end up making a copy with an ImmutableHashSet<T> or FrozenSet<T>.

Related:
#76028
#29387
#2293

API Proposal

namespace System.Collections.ObjectModel;

[DebuggerDisplay("Count = {Count}")]
public class ReadOnlySet<T> : IReadOnlySet<T>, ISet<T>, ICollection
{
    public ReadOnlySet(ISet<T> set);

    public static ReadOnlySet<T> Empty { get; }

    protected ISet<T> Set { get; }

    public int Count { get; }
    public IEnumerator<T> GetEnumerator();

    public bool Contains(T item);
    public bool IsProperSubsetOf(IEnumerable<T> other);
    public bool IsProperSupersetOf(IEnumerable<T> other);
    public bool IsSubsetOf(IEnumerable<T> other);
    public bool IsSupersetOf(IEnumerable<T> other);
    public bool Overlaps(IEnumerable<T> other);
    public bool SetEquals(IEnumerable<T> other);

    ... // explicit interface implementations of all other interface methods, throwing from mutating members
}

API Usage

HashSet<int> set = ...;
var ros = new ReadOnlySet<int>(set);

Alternative Designs

  • ISet<T> exposes CopyTo while IReadOnlySet<T> does not. ReadOnlySet<T> will implement it, but should it be implicit or explicitly implemented? (Alternatively/separately, should we consider adding CopyTo to IReadOnlyCollection<T> and thus implicitly to IReadOnlySet<T>?)
  • Do we also want an ReadOnlySet<T> AsReadOnly() on HashSet<T>? List<T> has ReadOnlyCollection<T> AsReadOnly() and there's a static ReadOnlyCollection<T> AsReadOnly(T[]) on Array, but Dictionary<> doesn't have an AsReadOnly.
  • Do we also want an extension method ReadOnlySet<T> AsReadOnly(this ISet<T>)? Such an extension exists for both IList<T> and IDictionary<>.
  • What reference assembly should this be exposed from? ReadOnlyCollection/Dictionary are both implemented in CoreLib and exposed via System.Runtime. Should this live there, too? Or in System.Collections.dll?

Risks

n/a

Metadata

Metadata

Assignees

Labels

api-approvedAPI was approved in API review, it can be implementedarea-System.Collectionsin-prThere is an active PR which will close this issue when it is merged

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions