C# 安全地返回字典引用

C# returning Dictionary references safely

我正在考虑三种方法来返回对内部 Dictionary 实例 (C#) 的引用,以考虑代码安全和对我正在从事的项目的代码 readability/visually 的影响。

我已将其缩小为以下三种方法,但我愿意接受更好的建议。目前我更喜欢 #3 作为没有额外样板的最佳安全平衡。

1) 使用第二个 ReadOnlyDictionary 实例来包装内部字典,只让 ReadOnlyDictionary 转义 class:

2) Return Dictionary 实例作为 IReadOnlyDictionary,但重铸将允许对其进行修改,因此不如选项 #1 或 #3 安全。

3) Return Dictionary.ToImmutableDictionary() 作为 ImmutableDictionary 当它转义包含 class 以便返回的对象是不可变的内部字典的视图,虽然这会为每次调用创建一个新副本,从而导致更高的成本,但对于小型简单字典(我的字典)应该没问题。

    private readonly Dictionary<string, string> innerDictionary = new Dictionary<string, string>();

    // Only required for Example #1
    private readonly IReadOnlyDictionary<string, string> readonlyInnerDictionary;

    public ExampleClass() {
        // Only required for Example #1
        readonlyInnerDictionary = new ReadOnlyDictionary<string, string>(innerDictionary);
    }   

    public IReadOnlyDictionary<string, string> GetExampleOne() {
        // Requires a second dictionary which is more boiler plate but the object being returned is truly readonly
        return readonlyInnerDictionary;     
    }

    public IReadOnlyDictionary<string, string> GetExampleTwo() {
        // Requires InnerDictionary be defined as Dictionary (Not IDictionary) but doesn't require the second dictionary be defined
        // which is less boiler plate, but the object returned could be re-cast to it's mutable form meaning it's not truly mutation safe.
        return innerDictionary;
    }

    public ImmutableDictionary<string, string> GetExampleThree() {
        // Truly immutable object returned, but a new instance is built for every call; fortunately all of my dictionaries are small (containing at most 9 keys)
        return innerDictionary.ToImmutableDictionary();
    }

选项 1 是可行的方法。您可以将 ReadOnlyDictionary 重铸为 IDictionary,但这会在尝试变异时抛出异常:

 void CastingTest()
        {
            var dic1 = new Dictionary<string, string>();
            dic1.Add("Key", "Value");
            var dic2 = new ReadOnlyDictionary<string, string>(dic1);
            var castedDic = (IDictionary<string, string>)dic2;
            castedDic.Add("AnotherKey", "Another Value"); //System.NotSupportedException, Collection is read only
        }

ReadOnlyDictionary 不会创建另一个词典。它指向与第一个相同的引用,封装它。所以如果你这样做:

void AddTest()
        {
            var dic1 = new Dictionary<string, string>();
            dic1.Add("Key", "Value");
            var dic2 = new ReadOnlyDictionary<string, string>(dic1);
            dic1.Add("Key2", "Value2"); //Now dic2 have 2 values too.
        }

永远不要暴露你的 innerDictionary,你会没事的。

确定最简洁、最简单、最安全;但不是最有效的解决方案是在内部使用 ConcurrentDictionary 确保线程安全(来自 System.Collections.Concurrent),然后使用 System.Collections.Immutable 调用 dictionary.ToImmutableDictionary() 创建字典逃离内部 class。接口签名用于 ImmutableDictionary<KeyType, ValueType>.

这不是最高效的解决方案,但在我的情况下,在大多数情况下,字典少于 12 个键和表示状态的小简单对象不是问题。