0

我正在考虑三种方法来返回对内部 Dictionary 实例 (C#) 的引用,这些方法涉及代码安全性以及对我正在处理的项目的代码可读性/视觉上的影响。

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

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

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

3)当 Dictionary.ToImmutableDictionary() 转义包含类时,将 Dictionary.ToImmutableDictionary() 作为 ImmutableDictionary 返回,以便返回的对象是内部字典的不可变视图,尽管这将为每次调用创建一个新副本,从而产生更高的成本,这应该没问题带有简单的小字典(我的字典)。

    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();
    }
4

2 回答 2

2

选项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,你会没事的。

于 2016-09-02T14:54:02.167 回答
0

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

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

于 2016-09-09T13:18:53.667 回答