【问题标题】:Making a SortedList readonly使 SortedList 只读
【发布时间】:2011-05-20 01:39:26
【问题描述】:

我经常有课程将列表公开为ReadOnlyCollection<T>s,即

public class Class
{
  List<string> list;

  public ReadOnlyCollection<string> TheList
  {
    get { return list.AsReadOnly(); }
  }
}

对于IDictionary&lt;T,U&gt;(例如SortedList&lt;string, string&gt;),最好的方法是什么?

【问题讨论】:

  • 接口与实现无关。 IDictionary&lt;T,U&gt; 按定义提供写入方法。因此,您无法将它们从中删除。

标签: c# dictionary sortedlist


【解决方案1】:
public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    private readonly IDictionary<TKey, TValue> sourceDictionary;

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

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

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

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

    public bool IsReadOnly
    {
        get { return true; }
    }

    public ReadOnlyDictionary(IDictionary<TKey, TValue> sourceDictionary)
    {
        AssertUtilities.ArgumentNotNull(sourceDictionary, "sourceDictionary");

        this.sourceDictionary = sourceDictionary;
    }

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

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

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

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

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

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

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

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

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

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

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

[编辑] @Simon Buchan 和@Cory Nelson 指出,对于那些不受支持的方法,最好使用隐式接口实现。相应地更新了代码。

【讨论】:

  • 干杯,我想我会通过更改从ReadOnlyCollection&lt;KeyValuePair&lt;TKey, TValue&gt;&gt;继承来做到这一点
  • @Matthew Finlay - 我建议不要这样做。您将失去字典的力量,例如优化搜索。
  • @Alex,只是好奇,你为什么要包含 Add()/Remove()/Clear() 并抛出 NSE?为什么不把它们放在一起呢?
  • @jb - 如果您有意外使用这些方法的用法,您宁愿崩溃以便了解错误,而不是有细微的错误。
  • 您应该将不受支持的方法设为私有。
【解决方案2】:

创建一个 ReadOnlyDictionary 类,该类将 IDictionary 实现为内部 Dictionary 实例的包装器。对于会修改字典的方法,抛出异常。实现 IsReadOnly 以返回 true。实现所有其他方法以传递给内部 Dictionary 实例。

【讨论】:

  • 我认为抛出异常不是一个好主意,因为它是一个运行时事件。
  • 我还建议让 IsReadOnly 和修改方法显式接口实现以匹配 ReadOnlyCollection:bool IDictionary&lt;TKey, TValue&gt;.IsReadOnly { get { return true; } }。如果将 getter 转发给隐式 getter,则可以显式实现 indexer setter:TValue IDictionary&lt;TKey, TValue&gt;.this[TKey key] { get { return this[key]; } set { throw InvalidOperationException(); } }
  • @zerkms:ReadOnlyCollection 在其显式实现上抛出 NotSupportedException("Collection is read-only.")
  • @Simon Buchan:是的,这不是静态检查。
【解决方案3】:

您可以使用标准的 LINQ 方法来做到这一点。

  1. 创建您的来源列表:

     List<String> myList = new List<String>() { "A", "B", "C" };
    
  2. 使用.ToDictionary linq 扩展方法将您的列表投影到字典中:

     var myDictionary = myList.ToDictionary(listItem => listItem);
    

注意:lambda 表达式从您的列表中窥视一个键(请记住,字典只能包含唯一键;否则请考虑使用表示列表字典的 ILookup)。

  1. 将你的字典改成一个 SortedDictionary 实例:

     var mySortedDictionary = new SortedDictionary<string, string>(myDictionary);
    
  2. 将您的排序字典公开为IReadOnlyDictionary 接口,如下所示:

     public IReadOnlyDictionary MemberDictionary { get; private set; );
    
     // ...somewhere in your constructor or class's initialization method...
     this.MemberDictionary = mySortedDictionary;
    

【讨论】:

    猜你喜欢
    • 2010-11-09
    • 1970-01-01
    • 2011-07-21
    • 2018-07-16
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    • 1970-01-01
    相关资源
    最近更新 更多