2016-04-23 24 views
4

ここでは、このサンプルコードです:C#HashSetの<T>読み取り専用の回避策

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(); 
     } 
    } 
} 

そしてここでは、テストコードです:

// 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"プロパティのために?

マイクロソフトでは、「AsReadOnly」メソッドをHashSetに実装しますか<T>?

+0

[ImmutableHashSet](https://msdn.microsoft.com/en-us/library/dn467171(v=11111).aspx) –

+0

あなた自身で書くこともそれほど難しくありません:https: //github.com/airbreather/AirBreather.Common/blob/aba09330ae3066cb46ad7e0ee963e00d27e63cb6/Source/AirBreather.Common/AirBreather.Common/Collections/ReadOnlySet.cs https://github.com/airbreather/AirBreather.Common/blob/aba09330ae3066cb46ad7e0ee963e00d27e63cb6/Source /AirBreather.Common/AirBreather.Common/Utilities/EnumerableUtility.cs#L47 –

答えて

6

は、ここでは、CodeContractsを使用していない場合は最初の行が必要すらない.AsReadOnly()

public ReadOnlyCollection<T> AsReadOnly() { 
    Contract.Ensures(Contract.Result<ReadOnlyCollection<T>>() != null); 
    return new ReadOnlyCollection<T>(this); 
} 

the entirety of the codeです。ただし、ReadOnlyCollection<T>IList<T>のみをサポートします。HashSet<T>はサポートしていません。

私が行うことはISet<T>を取り、読み取り操作like ReadOnlyCollection<T> does internallyを通過する独自のReadOnlySet<T>クラスを作ることです。

UPDATE

:ここ は完全に私はすぐに実装して何にでも上.AsReadOnly()を追加する拡張メソッドと一緒に書いたReadOnlySet<T>肉付けされISet<T>

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; } 
    } 
} 
1

あなたはの独自の実装を書くことができますその後

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; } 
} 

IEnumerable<T>カウントをラップIReadOnlyCollection<T>あなたはこのようなあなたのReadonlyHashSetプロパティを宣言:

public static IReadOnlyCollection<String> ReadonlyHashSet 
{ 
    get { return new ReadOnlyCollectionFromEnumerable<string>(strHashSet, strHashSet.Count); } 
} 

私はそれが問題を解決するだろうと思います。

+0

'ICollection 'を渡す方が、 'HashSetの最も強力な部分である' .Contains( ' –

+0

@ScottChamberlain戻り値の型はOPと同じです。もちろん、Contains()は、IReadOnlyCollectionのメンバーではありません'。私は、その値がプロパティ(IsReadOnly')を経由するのではなく、その型を通して読み込み専用であることをOPが示したかったとします。 –

+0

ああ、私は 'ReadOnlyCollection '(https:// msdn.microsoft.com/en-us/library/ms132478(v=vs.110).aspx)ではなく、 'IReadOnlyCollection ' –

関連する問題