首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C# HashSet<T>只读解决方案

C# HashSet<T>只读解决方案
EN

Stack Overflow用户
提问于 2016-04-23 18:54:43
回答 5查看 9.9K关注 0票数 14

下面是这个示例代码:

代码语言:javascript
运行
复制
static class Store
{
    private static List<String> strList = new List<string>();
    private static HashSet<String> strHashSet = new HashSet<string>();

    public static List<String> NormalList
    {
        get { return strList; }
    }

    public static HashSet<String> NormalHashSet
    {
        get { return strHashSet; }
    }

    public static IReadOnlyList<String> ReadonlyList
    {
        get { return (IReadOnlyList<String>)strList; }
    }

    public static IReadOnlyCollection<String> ReadonlyHashSet
    {
        get { return (IReadOnlyCollection<String>)strHashSet; }
    }

    public static IReadOnlyList<String> Real_ReadonlyList
    {
        get { return (IReadOnlyList<String>)strList.AsReadOnly(); }
    }

    public static IReadOnlyCollection<String> Real_ReadonlyHashSet
    {
        get
        {
            List<String> tmpList = new List<String>(strHashSet);
            return (IReadOnlyList<String>)(tmpList).AsReadOnly();
        }
    }
}

下面是一个测试代码:

代码语言:javascript
运行
复制
// normal behaviour
// you can modify the list and the hashset

Store.NormalList.Add("some string 1");

Store.NormalHashSet.Add("some string 1");

// tricky behaviour
// you can still modify the list and the hashset

((List<String>)Store.ReadonlyList).Add("some string 2");

((HashSet<String>)Store.ReadonlyHashSet).Add("some string 2");

// expected read-only behaviour
// you can NOT modify

// throws InvalidCastException
((List<String>)Store.Real_ReadonlyList).Add("some string 3");
// throws InvalidCastException
((HashSet<String>)Store.Real_ReadonlyHashSet).Add("some string 3");

我的问题是:

"Real_ReadonlyHashSet“属性有更好的解决方案吗?

微软有一天会在HashSet上实现“HashSet”方法吗?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2016-04-23 19:18:15

这里是代码的全部 of .AsReadOnly()

代码语言:javascript
运行
复制
public ReadOnlyCollection<T> AsReadOnly() {
    Contract.Ensures(Contract.Result<ReadOnlyCollection<T>>() != null);
    return new ReadOnlyCollection<T>(this);
}

如果不使用CodeContracts,甚至没有必要使用第一行。但是,ReadOnlyCollection<T>只支持HashSet<T>不支持的IList<T>

我要做的是创建您自己的ReadOnlySet<T>类,它接受一个ISet<T>,并且只通过读操作在内部

更新:这里的是一个完全充实的ReadOnlySet<T>,我很快编写了一个扩展方法,将.AsReadOnly()添加到实现ISet<T>的任何东西上

代码语言:javascript
运行
复制
public static class SetExtensionMethods
{
    public static ReadOnlySet<T> AsReadOnly<T>(this ISet<T> set)
    {
        return new ReadOnlySet<T>(set);
    }
}

public class ReadOnlySet<T> : IReadOnlyCollection<T>, ISet<T>
{
    private readonly ISet<T> _set;
    public ReadOnlySet(ISet<T> set)
    {
        _set = set;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _set.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable) _set).GetEnumerator();
    }

    void ICollection<T>.Add(T item)
    {
        throw new NotSupportedException("Set is a read only set.");
    }

    public void UnionWith(IEnumerable<T> other)
    {
        throw new NotSupportedException("Set is a read only set.");
    }

    public void IntersectWith(IEnumerable<T> other)
    {
        throw new NotSupportedException("Set is a read only set.");
    }

    public void ExceptWith(IEnumerable<T> other)
    {
        throw new NotSupportedException("Set is a read only set.");
    }

    public void SymmetricExceptWith(IEnumerable<T> other)
    {
        throw new NotSupportedException("Set is a read only set.");
    }

    public bool IsSubsetOf(IEnumerable<T> other)
    {
        return _set.IsSubsetOf(other);
    }

    public bool IsSupersetOf(IEnumerable<T> other)
    {
        return _set.IsSupersetOf(other);
    }

    public bool IsProperSupersetOf(IEnumerable<T> other)
    {
        return _set.IsProperSupersetOf(other);
    }

    public bool IsProperSubsetOf(IEnumerable<T> other)
    {
        return _set.IsProperSubsetOf(other);
    }

    public bool Overlaps(IEnumerable<T> other)
    {
        return _set.Overlaps(other);
    }

    public bool SetEquals(IEnumerable<T> other)
    {
        return _set.SetEquals(other);
    }

    public bool Add(T item)
    {
        throw new NotSupportedException("Set is a read only set.");
    }

    public void Clear()
    {
        throw new NotSupportedException("Set is a read only set.");
    }

    public bool Contains(T item)
    {
        return _set.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        _set.CopyTo(array, arrayIndex);
    }

    public bool Remove(T item)
    {
        throw new NotSupportedException("Set is a read only set.");
    }

    public int Count
    {
        get { return _set.Count; }
    }

    public bool IsReadOnly
    {
        get { return true; }
    }
}
票数 15
EN

Stack Overflow用户

发布于 2022-06-03 06:36:54

从.NET 5开始,HashSet类现在实现了IReadOnlySet接口。但是没有内置的ReadOnlySet<T>包装器,类似于字典的现有ReadOnlyDictionary类,但是实现一个非常简单:

代码语言:javascript
运行
复制
public class ReadOnlySet<T> : IReadOnlySet<T>
{
    private readonly ISet<T> _set;
    public ReadOnlySet(ISet<T> set) { ArgumentNullException.ThrowIfNull(set); _set = set; }

    public int Count => _set.Count;
    public bool Contains(T item) => _set.Contains(item);
    public bool IsProperSubsetOf(IEnumerable<T> other) => _set.IsProperSubsetOf(other);
    public bool IsProperSupersetOf(IEnumerable<T> other) => _set.IsProperSupersetOf(other);
    public bool IsSubsetOf(IEnumerable<T> other) => _set.IsSubsetOf(other);
    public bool IsSupersetOf(IEnumerable<T> other) => _set.IsSupersetOf(other);
    public bool Overlaps(IEnumerable<T> other) => _set.Overlaps(other);
    public bool SetEquals(IEnumerable<T> other) => _set.SetEquals(other);
    public IEnumerator<T> GetEnumerator() => _set.GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

即将发布的.NET 7还将为IDictionary<TKey,TValue>提供一个新的AsReadOnly扩展方法,因此我们也为ISet<T>提供一个扩展方法:

代码语言:javascript
运行
复制
public static ReadOnlySet<T> AsReadOnly<T>(this ISet<T> set) => new ReadOnlySet<T>(set);

用法示例:

代码语言:javascript
运行
复制
HashSet<Item> items = new();
ReadOnlySet<Item> readOnlyItems = items.AsReadOnly();
票数 2
EN

Stack Overflow用户

发布于 2016-04-23 19:25:00

您可以编写自己的IReadOnlyCollection<T>实现,它包装了一个IEnumerable<T>和一个计数:

代码语言:javascript
运行
复制
public sealed class ReadOnlyCollectionFromEnumerable<T>: IReadOnlyCollection<T>
{
    readonly IEnumerable<T> _data;

    public ReadOnlyCollectionFromEnumerable(IEnumerable<T> data, int count)
    {
        _data = data;
        Count = count;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _data.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public int Count { get; }
}

然后像这样声明您的ReadonlyHashSet属性:

代码语言:javascript
运行
复制
public static IReadOnlyCollection<String> ReadonlyHashSet
{
    get { return new ReadOnlyCollectionFromEnumerable<string>(strHashSet, strHashSet.Count); }
}

我认为这样可以解决这个问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36815062

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档