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 个键和表示状态的小简单对象不是问题。
我正在考虑三种方法来返回对内部 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 个键和表示状态的小简单对象不是问题。