읽기 전용 속성에서 사전에 대한 참조를 반환합니다. 소비자가 내 데이터를 변경하지 못하게하려면 어떻게합니까? 이것이 있다면 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 가지가 있습니다.
IDictionary<TKey, TValue>
제안 된대로 사용자 정의 읽기 전용을 구현하고 내부 사전에 랩 / 위임ICollection<KeyValuePair<TKey,
세트를 읽기 전용으로 또는
TValue>>
IEnumerable<KeyValuePair<TKey,
값 사용에 따라 반환
TValue>>- 복사 생성자를 사용하여 사전을 복제하고 사본
.ctor(IDictionary<TKey,
을 리턴하십시오. 사용자가 원하는대로 자유롭게 사용할 수 있으며 소스 사전을 호스트하는 오브젝트의 상태에 영향을 미치지 않습니다. 복제중인 사전에 참조 유형 (예제에 표시된 문자열이 아님)이 포함 된 경우 “수동으로”복사를 수행하고 참조 유형도 복제해야합니다.
TValue>)
여담으로; 컬렉션을 노출 할 때 가능한 가장 작은 인터페이스를 노출하는 것을 목표로합니다. 예제의 경우 유형이 노출하는 공개 계약을 위반하지 않고 기본 구현을 변경할 수 있으므로 IDictionary 여야합니다.
답변
읽기 전용 사전은 어느 정도 대체 될 수 있습니다 Func<TKey, TValue>
.-검색을 수행하는 사람들 만 원할 경우 일반적으로 API에서이를 사용합니다. 간단하고, 특히 원하는 경우 백엔드를 교체하는 것이 간단합니다. 그러나 키 목록은 제공하지 않습니다. 중요한 것은 당신이하는 일에 달려 있습니다.
답변
아니요,하지만 쉽게 롤업 할 수 있습니다. IDictionary는 IsReadOnly 속성을 정의합니다. 사전을 포장하고 적절한 메소드에서 NotSupportedException을 던지기 만하면됩니다.