[.net] .NET에 사용 가능한 읽기 전용 일반 사전이 있습니까?

읽기 전용 속성에서 사전에 대한 참조를 반환합니다. 소비자가 내 데이터를 변경하지 못하게하려면 어떻게합니까? 이것이 있다면 IList나는 단순히 그것을 반환 할 수 AsReadOnly있습니다. 사전으로 할 수있는 일이 있습니까?

Private _mydictionary As Dictionary(Of String, String)
Public ReadOnly Property MyDictionary() As Dictionary(Of String, String)
    Get
        Return _mydictionary
    End Get
End Property



답변

다음은 사전을 감싸는 간단한 구현입니다.

public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    private readonly IDictionary<TKey, TValue> _dictionary;

    public ReadOnlyDictionary()
    {
        _dictionary = new Dictionary<TKey, TValue>();
    }

    public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
    {
        _dictionary = dictionary;
    }

    #region IDictionary<TKey,TValue> Members

    void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
    {
        throw ReadOnlyException();
    }

    public bool ContainsKey(TKey key)
    {
        return _dictionary.ContainsKey(key);
    }

    public ICollection<TKey> Keys
    {
        get { return _dictionary.Keys; }
    }

    bool IDictionary<TKey, TValue>.Remove(TKey key)
    {
        throw ReadOnlyException();
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        return _dictionary.TryGetValue(key, out value);
    }

    public ICollection<TValue> Values
    {
        get { return _dictionary.Values; }
    }

    public TValue this[TKey key]
    {
        get
        {
            return _dictionary[key];
        }
    }

    TValue IDictionary<TKey, TValue>.this[TKey key]
    {
        get
        {
            return this[key];
        }
        set
        {
            throw ReadOnlyException();
        }
    }

    #endregion

    #region ICollection<KeyValuePair<TKey,TValue>> Members

    void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
    {
        throw ReadOnlyException();
    }

    void ICollection<KeyValuePair<TKey, TValue>>.Clear()
    {
        throw ReadOnlyException();
    }

    public bool Contains(KeyValuePair<TKey, TValue> item)
    {
        return _dictionary.Contains(item);
    }

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        _dictionary.CopyTo(array, arrayIndex);
    }

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

    public bool IsReadOnly
    {
        get { return true; }
    }

    bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
    {
        throw ReadOnlyException();
    }

    #endregion

    #region IEnumerable<KeyValuePair<TKey,TValue>> Members

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

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

    #endregion

    private static Exception ReadOnlyException()
    {
        return new NotSupportedException("This dictionary is read-only");
    }
}


답변

.NET 4.5

.NET Framework 4.5 BCL에 ReadOnlyDictionary<TKey, TValue>( source )가 도입되었습니다 .

.NET Framework 4.5 BCL에는 AsReadOnly사전 용이 포함되어 있지 않으므로 원하는 경우 직접 작성해야합니다. 다음과 같을 것입니다. 단순성은 아마도 .NET 4.5의 우선 순위가 아닌 이유를 강조합니다.

public static ReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(
    this IDictionary<TKey, TValue> dictionary)
{
    return new ReadOnlyDictionary<TKey, TValue>(dictionary);
}

.NET 4.0 이하

.NET 4.5 이전 Dictionary<TKey, TValue>에는 ReadOnlyCollection을 감싸는 것처럼 List 를 감싸는 .NET Framework 클래스가 없습니다 . 그러나 하나를 만드는 것은 어렵지 않습니다.

다음은 예 입니다. Google이 ReadOnlyDictionary를 사용하는 경우 많은 다른 것들이 있습니다 .


답변

최근 BUILD 컨퍼런스 에서 .NET 4.5 이후 인터페이스 System.Collections.Generic.IReadOnlyDictionary<TKey,TValue>가 포함 되었다고 발표 되었습니다. 증명은 여기 (Mono)와 여기 (Microsoft)입니다.)

ReadOnlyDictionary포함되어 있는지 확실하지 않지만 적어도 인터페이스를 사용하면 공식 .NET 일반 인터페이스를 제공하는 구현을 만드는 것이 어렵지 않아야합니다. 🙂


답변

간단한 래퍼를 사용하십시오. IDictionary를 구현하지 않으므로 런타임에 사전을 변경하는 사전 메서드에 대해 예외를 throw하지 않아도됩니다. 변경 방법은 단순히 존재하지 않습니다. IReadOnlyDictionary라는 자체 인터페이스를 만들었습니다.

public interface IReadOnlyDictionary<TKey, TValue> : IEnumerable
{
    bool ContainsKey(TKey key);
    ICollection<TKey> Keys { get; }
    ICollection<TValue> Values { get; }
    int Count { get; }
    bool TryGetValue(TKey key, out TValue value);
    TValue this[TKey key] { get; }
    bool Contains(KeyValuePair<TKey, TValue> item);
    void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex);
    IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator();
}

public class ReadOnlyDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>
{
    readonly IDictionary<TKey, TValue> _dictionary;
    public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
    {
        _dictionary = dictionary;
    }
    public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); }
    public ICollection<TKey> Keys { get { return _dictionary.Keys; } }
    public bool TryGetValue(TKey key, out TValue value) { return _dictionary.TryGetValue(key, out value); }
    public ICollection<TValue> Values { get { return _dictionary.Values; } }
    public TValue this[TKey key] { get { return _dictionary[key]; } }
    public bool Contains(KeyValuePair<TKey, TValue> item) { return _dictionary.Contains(item); }
    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { _dictionary.CopyTo(array, arrayIndex); }
    public int Count { get { return _dictionary.Count; } }
    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return _dictionary.GetEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator() { return _dictionary.GetEnumerator(); }
}


답변

isReadOnly의상의 IDictionary<TKey,TValue>로부터 상속된다 ICollection<T>( IDictionary<TKey,TValue>연장 ICollection<T>같이 ICollection<KeyValuePair<TKey,TValue>>). 어떤 식 으로든 사용되거나 구현되지 않으며 실제로 연관된 ICollection<T>멤버 를 명시 적으로 구현하여 “숨겨져”있습니다 .

문제를 해결하기 위해 볼 수있는 방법은 적어도 3 가지가 있습니다.

  1. IDictionary<TKey, TValue>제안 된대로 사용자 정의 읽기 전용을 구현하고 내부 사전에 랩 / 위임
  2. ICollection<KeyValuePair<TKey,
    TValue>>
    세트를 읽기 전용으로 또는
    IEnumerable<KeyValuePair<TKey,
    TValue>>
    값 사용에 따라 반환
  3. 복사 생성자를 사용하여 사전을 복제하고 사본 .ctor(IDictionary<TKey,
    TValue>)
    을 리턴하십시오. 사용자가 원하는대로 자유롭게 사용할 수 있으며 소스 사전을 호스트하는 오브젝트의 상태에 영향을 미치지 않습니다. 복제중인 사전에 참조 유형 (예제에 표시된 문자열이 아님)이 포함 된 경우 “수동으로”복사를 수행하고 참조 유형도 복제해야합니다.

여담으로; 컬렉션을 노출 할 때 가능한 가장 작은 인터페이스를 노출하는 것을 목표로합니다. 예제의 경우 유형이 노출하는 공개 계약을 위반하지 않고 기본 구현을 변경할 수 있으므로 IDictionary 여야합니다.


답변

읽기 전용 사전은 어느 정도 대체 될 수 있습니다 Func<TKey, TValue>.-검색을 수행하는 사람들 만 원할 경우 일반적으로 API에서이를 사용합니다. 간단하고, 특히 원하는 경우 백엔드를 교체하는 것이 간단합니다. 그러나 키 목록은 제공하지 않습니다. 중요한 것은 당신이하는 일에 달려 있습니다.


답변

아니요,하지만 쉽게 롤업 할 수 있습니다. IDictionary는 IsReadOnly 속성을 정의합니다. 사전을 포장하고 적절한 메소드에서 NotSupportedException을 던지기 만하면됩니다.