ProgramingTip

C #에 변경 불가능한 사전을 제공하는 방법이 있습니까?

bestdevel 2020. 11. 8. 10:38
반응형

C #에 변경 불가능한 사전을 제공하는 방법이 있습니까?


변경 불가능한 사전을 제공 할 수있는 핵심 C # 라이브러리에 내장 된 있습니까?

자바의 라인을 따라 뭔가 :

Collections.unmodifiableMap(myMap);

그리고 업그레이드하기 위해 키 / 값 자체가 변경되는 것을 막으려는 것이 아니라 사전의 구조뿐입니다. IDictionary mutator 메서드 중 하나가 호출을 빨리 성공적으로 실패하는 경우를 원합니다 ( Add, Remove, Clear).


아니요,하지만 래퍼는 다소 사소합니다.

public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    IDictionary<TKey, TValue> _dict;

    public ReadOnlyDictionary(IDictionary<TKey, TValue> backingDict)
    {
        _dict = backingDict;
    }

    public void Add(TKey key, TValue value)
    {
        throw new InvalidOperationException();
    }

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

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

    public bool Remove(TKey key)
    {
        throw new InvalidOperationException();
    }

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

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

    public TValue this[TKey key]
    {
        get { return _dict[key]; }
        set { throw new InvalidOperationException(); }
    }

    public void Add(KeyValuePair<TKey, TValue> item)
    {
        throw new InvalidOperationException();
    }

    public void Clear()
    {
        throw new InvalidOperationException();
    }

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

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

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

    public bool IsReadOnly
    {
        get { return true; }
    }

    public bool Remove(KeyValuePair<TKey, TValue> item)
    {
        throw new InvalidOperationException();
    }

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

    System.Collections.IEnumerator 
           System.Collections.IEnumerable.GetEnumerator()
    {
        return ((System.Collections.IEnumerable)_dict).GetEnumerator();
    }
}

값 수정을 허용하는 위의이 [] setter를 사용할 수 있습니다.


내가 아는 한 없습니다. 그러나 다음 기사에서 일부 코드를 복사하고 많이 배울 수 있습니다.

C #의 불변성 1 부 : C #의 불변성의 종류
2 부 : C #의 단순 불변
스택 불변성 3 부 : C #의 공 변성 불변 스택
불변성 4 부 : C #의 불변
큐 불변성 6 부 : 간단한 이진 트리
불변성 C # 파트 7 : 이진 트리에 대한 추가 정보
C # 파트 8 : 이진 트리에 대한 추가 정보
C #의 불변성 파트 9 : 학술? 또한 내 AVL 트리 구현
C #의 불변성 파트 10 : C #의 이중 종료 보류
불변성 파트 11 : 작동하는 이중 종료 대기열


.NET 4.5 출시와 함께 새로운 ReadOnlyDictionary 클래스가 있습니다. 생성자 IDictionary전달 하여 변경 불가능한 사전을 만듭니다.

다음 은 읽기 전용 사전 생성을 단순화하는 데 사용할 수있는 유용한 확장 방법입니다.


나는 그렇게 생각하지 않는다. 읽기 전용 목록과 읽기 전용 컬렉션을 만드는 방법이 읽기 전용 사전이 내장되어 있다고 생각하지 않습니다. System.ServiceModel에는 ReadOnlyDictinoary 구현이 있습니다. 아마도 Reflector를 사용하여 복사하거나 처음부터 직접 만드는 것이 너무 어렵지 않을 것입니다. 기본적으로 사전을 래핑하고 mutator가 호출 될 때 발생합니다.


dbkk의 답변에 추가하여 ReadOnlyDictionary를 처음 만들 때 사용할 때 이니셜 라이저를 사용할 수 있습니다. 다음과 같이 수정했습니다.

private readonly int _finalCount;

/// <summary>
/// Takes a count of how many key-value pairs should be allowed.
/// Dictionary can be modified to add up to that many pairs, but no
/// pair can be modified or removed after it is added.  Intended to be
/// used with an object initializer.
/// </summary>
/// <param name="count"></param>
public ReadOnlyDictionary(int count)
{
    _dict = new SortedDictionary<TKey, TValue>();
    _finalCount = count;
}

/// <summary>
/// To allow object initializers, this will allow the dictionary to be
/// added onto up to a certain number, specifically the count set in
/// one of the constructors.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void Add(TKey key, TValue value)
{
    if (_dict.Keys.Count < _finalCount)
    {
        _dict.Add(key, value);
    }
    else
    {
        throw new InvalidOperationException(
            "Cannot add pair <" + key + ", " + value + "> because " +
            "maximum final count " + _finalCount + " has been reached"
        );
    }
}

이제 다음과 같이 클래스를 사용할 수 있습니다.

ReadOnlyDictionary<string, string> Fields =
    new ReadOnlyDictionary<string, string>(2)
        {
            {"hey", "now"},
            {"you", "there"}
        };

오픈 소스 PowerCollections 라이브러리에는 클래스 의 정적 ReadOnly()메서드를 통해 액세스 할 수있는 읽기 전용 사전 래퍼 (다른 거의 모든 항목에 대한 읽기 전용 래퍼 포함)가 포함되어 있습니다 Algorithms.


한 가지 해결 방법은 사전에서 새 KeyValuePair 목록을 던져 원본을 수정하지 않은 상태로 유지하는 것입니다.

var dict = new Dictionary<string, string>();

dict.Add("Hello", "World");
dict.Add("The", "Quick");
dict.Add("Brown", "Fox");

var dictCopy = dict.Select(
    item => new KeyValuePair<string, string>(item.Key, item.Value));

// returns dictCopy;

이렇게하면 원본 사전이 수정되지 않습니다.


"즉시 사용할 수있는"방법은 없습니다. 고유 한 Dictionary 클래스를 파생하고 필요한 제한 사항을 구현하여 만들 수 있습니다.


여기에서 C # 용 AVLTree의 Inmutable (READONLY 아님) 구현 구현을 찾았습니다.

AVL 트리는 각 작업에 대한 대수 (일정하지 않음) 비용이 있지만 여전히 빠릅니다.

http://csharpfeeds.com/post/7512/Immutability_in_Csharp_Part_Nine_Academic_Plus_my_AVL_tree_implementation.aspx


Linq 이후에는 일반 인터페이스 ILookup이 있습니다. MSDN 에서 자세히 알아보십시오 .

따라서 단순히 불변 사전을 얻으려면 다음을 호출 할 수 있습니다.

using System.Linq;
// (...)
var dictionary = new Dictionary<string, object>();
// (...)
var read_only = dictionary.ToLookup(kv => kv.Key, kv => kv.Value);

다음과 같이 시도해 볼 수 있습니다.

private readonly Dictionary<string, string> _someDictionary;

public IEnumerable<KeyValuePair<string, string>> SomeDictionary
{
    get { return _someDictionary; }
}

이렇게하면 호출자가 자신의 사전으로 변환해야하는 변경 가능성 문제가 제거됩니다.

foo.SomeDictionary.ToDictionary(kvp => kvp.Key);

... 또는 인덱스 조회보다는 키에 대한 비교 연산을 사용하십시오. 예 :

foo.SomeDictionary.First(kvp => kvp.Key == "SomeKey");

일반적으로 사전에 어떤 사전도 전달하지 않는 것이 훨씬 좋습니다 (필요하지 않은 경우).

대신- 사전을 수정 하는 메소드를 제공하지 않는 인터페이스를 사용하여 도메인 객체를 만듭니다 (랩핑). 대신 키로 사전에서 요소를 검색하는 필수 조회 방법을 제공합니다 (보너스로 사전보다 사용하기가 더 쉽습니다).

public interface IMyDomainObjectDictionary 
{
    IMyDomainObject GetMyDomainObject(string key);
}

internal class MyDomainObjectDictionary : IMyDomainObjectDictionary 
{
    public IDictionary<string, IMyDomainObject> _myDictionary { get; set; }
    public IMyDomainObject GetMyDomainObject(string key)         {.._myDictionary .TryGetValue..etc...};
}

내가 설명한대로 또 다른 대안이 있습니다.

http://www.softwarerockstar.com/2010/10/readonlydictionary-tkey-tvalue/

기본적으로 ReadOnlyCollection>의 하위 클래스로, 작업을보다 우아한 방식으로 수행합니다. 그 안에있는 항목을 수정하는 메서드에서 예외를 발생시키는 대신 Dictionary를 읽기 전용으로 만들기위한 컴파일 타임 지원이 있다는 점에서 우아합니다.

참고 URL : https://stackoverflow.com/questions/35002/does-c-sharp-have-a-way-of-giving-me-an-immutable-dictionary

반응형