当前位置:  开发笔记 > 编程语言 > 正文

.NET中是否有只读通用字典?

如何解决《.NET中是否有只读通用字典?》经验,为你挑选了6个好方法。

我在我的只读属性中返回对字典的引用.如何防止消费者更改我的数据?如果这是一个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

Jeff Yates.. 230

.NET 4.5

.NET Framework 4.5 BCL介绍ReadOnlyDictionary(源代码).

由于.NET Framework 4.5 BCL不包含AsReadOnlyfor词典,因此您需要编写自己的(如果需要).它将类似于以下内容,其简单性可能突出了它为什么不是.NET 4.5的优先级.

public static ReadOnlyDictionary AsReadOnly(
    this IDictionary dictionary)
{
    return new ReadOnlyDictionary(dictionary);
}

.NET 4.0及更低版本

在.NET 4.5之前,没有.NET框架类包装Dictionary类似于ReadOnlyCollection包装List.但是,创建一个并不困难.

这是一个例子 - 如果你是谷歌的ReadOnlyDictionary,还有很多其他的.



1> Jeff Yates..:

.NET 4.5

.NET Framework 4.5 BCL介绍ReadOnlyDictionary(源代码).

由于.NET Framework 4.5 BCL不包含AsReadOnlyfor词典,因此您需要编写自己的(如果需要).它将类似于以下内容,其简单性可能突出了它为什么不是.NET 4.5的优先级.

public static ReadOnlyDictionary AsReadOnly(
    this IDictionary dictionary)
{
    return new ReadOnlyDictionary(dictionary);
}

.NET 4.0及更低版本

在.NET 4.5之前,没有.NET框架类包装Dictionary类似于ReadOnlyCollection包装List.但是,创建一个并不困难.

这是一个例子 - 如果你是谷歌的ReadOnlyDictionary,还有很多其他的.


它们看起来并不像在通常的`Dictionary <,>`上创建`AsReadOnly()`方法,所以我想知道有多少人会发现他们的新类型.不过,这个Stack Overflow线程会有所帮助.

2> Thomas Leves..:

这是一个包装字典的简单实现:

public class ReadOnlyDictionary : IDictionary
{
    private readonly IDictionary _dictionary;

    public ReadOnlyDictionary()
    {
        _dictionary = new Dictionary();
    }

    public ReadOnlyDictionary(IDictionary dictionary)
    {
        _dictionary = dictionary;
    }

    #region IDictionary Members

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

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

    public ICollection Keys
    {
        get { return _dictionary.Keys; }
    }

    bool IDictionary.Remove(TKey key)
    {
        throw ReadOnlyException();
    }

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

    public ICollection Values
    {
        get { return _dictionary.Values; }
    }

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

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

    #endregion

    #region ICollection> Members

    void ICollection>.Add(KeyValuePair item)
    {
        throw ReadOnlyException();
    }

    void ICollection>.Clear()
    {
        throw ReadOnlyException();
    }

    public bool Contains(KeyValuePair item)
    {
        return _dictionary.Contains(item);
    }

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

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

    public bool IsReadOnly
    {
        get { return true; }
    }

    bool ICollection>.Remove(KeyValuePair item)
    {
        throw ReadOnlyException();
    }

    #endregion

    #region IEnumerable> Members

    public IEnumerator> 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");
    }
}


@askheaves:很好的观察,但在Read Only类型中使用原始引用实际上非常有用 - 在私有变量中保留原始变量并为外部使用者修改它.例如,查看内置的ReadOnlyObservableCollection或ReadOnlyCollection对象:Thomas提供的内容与.Net框架固有的内容完全相同.谢谢托马斯!+1
@Samuel:用于创建一个空的只读字典.
注意那个构造函数.如果您执行传入的字典的引用副本,则外部代码可以修改"只读"字典.您的构造函数应该对参数执行完整,深入的副本.
@ user420667:它的实现方式,它是"非只读字典的只读视图".其他一些代码可能会更改原始字典的内容,这些更改将反映在只读字典中.它可能是理想的行为,取决于你想要实现的目标......
+1用于发布完整代码而不仅仅是链接,但我很好奇,ReadOnlyDictionary中空构造函数的重点是什么?:-)
@Thomas:这与.NET BCL中的ReadOnlyCollection相同.它是可能可变集合的只读视图.ReadOnly并不意味着不可预期的不可变性和不变性.
我建议将所有NotSupported方法实现为显式接口实现,以便它们更难调用.
我建议在你的Add,Remove,Clear和this [] setter实现之前放置`[Obsolete("ReadOnlyDictionaries"不支持,真实)]`attributues.这样,调用者在尝试使用这些方法时会收到编译时错误.这与您将按原样获得的运行时错误相反.
@ user2023861,这些方法已经被声明为显式接口实现,因此不能直接从类型为ReadOnlyDictionary <TKey,TValue>的变量中调用它们。只能从IDictionary <TKey,TValue>`类型的变量中调用它们,显然我不能在接口上添加这些属性...
@askheaves [`ImmutableDictionary `](http://msdn.microsoft.com/en-us/library/dn467181(v = vs.111).aspx)

3> knocte..:

在最近的BUILD会议上宣布,自.NET 4.5以来,System.Collections.Generic.IReadOnlyDictionary包含了界面.证明在这里(单声道)和这里(微软);)

不确定是否ReadOnlyDictionary也包括在内,但至少在界面上创建一个暴露官方.NET通用接口的实现应该不难.


`ReadOnlyDictionary `(.Net 4.5) - http://msdn.microsoft.com/en-us/library/gg712875.aspx

4> Dale Barnard..:

随意使用我的简单包装.它不实现IDictionary,因此它不必在运行时为可能更改字典的字典方法抛出异常.改变方法根本不存在.我为它创建了自己的界面,名为IReadOnlyDictionary.

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

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


+1不违反`IDictionary`合同.我认为从OOP的角度来看,对于`IDictionary`继承自`IReadOnlyDictionary`更为正确.

5> Neal..:

IsReadOnly on IDictionary继承自ICollection(IDictionaryextends ICollectionas ICollection>).它不以任何方式使用或实现(实际上通过使用显式实现关联ICollection成员来"隐藏" ).

我可以通过至少3种方式来解决问题:

    按照建议实现自定义只读IDictionary和包装/委托给内部字典

    ICollection>集合返回 为只读或 IEnumerable>取决于值的使用

    使用复制构造函数克隆字典.ctor(IDictionary)并返回副本 - 这样用户可以随意使用它,并且它不会影响托管源字典的对象的状态.请注意,如果要克隆的字典包含引用类型(不是示例中所示的字符串),则需要"手动"复制并克隆引用类型.

作为旁白; 在暴露集合时,旨在暴露最小的可能接口 - 在示例中它应该是IDictionary,因为这允许您在不破坏类型公开的公共合同的情况下改变底层实现.



6> Eamon Nerbon..:

只读字典可以在某种程度上替换为Func- 如果我只希望人们执行查找,我通常在API中使用它.它很简单,特别是,如果您愿意,更换后端很简单.但是,它没有提供密钥列表; 这是否重要取决于你在做什么.

推荐阅读
夏晶阳--艺术
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有