C#安全地返回字典引用

C#安全地返回字典引用,c#,dictionary,immutable-collections,C#,Dictionary,Immutable Collections,我正在考虑三种方法来返回对内部字典实例(C#)的引用,这涉及到代码安全性以及对我所从事项目的代码可读性/可视性的影响 我已经将范围缩小到以下三种方法,但我愿意接受更好的建议。目前我更喜欢#3作为没有额外锅炉板的最佳安全平衡 1)使用第二个ReadOnlyDictionary实例包装内部字典,只允许ReadOnlyDictionary转义类: 2)将字典实例作为IReadOnlyDictionary返回,但重铸将允许对其进行修改,因此不会像选项1或3那样安全 3)返回Dictionary.ToIm

我正在考虑三种方法来返回对内部字典实例(C#)的引用,这涉及到代码安全性以及对我所从事项目的代码可读性/可视性的影响

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

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

2)将字典实例作为IReadOnlyDictionary返回,但重铸将允许对其进行修改,因此不会像选项1或3那样安全

3)返回Dictionary.ToImmutableDictionary()作为不可变的Dictionary,当它转义包含类时,因此返回的对象是内部Dictionary的不可变视图,尽管这会为每次调用生成新的副本,从而产生更高的成本,但对于小的简单Dictionary(我的是这样的)应该没问题

private readonly Dictionary innerDictionary=new Dictionary();
//仅适用于示例#1
私人只读IReadOnlyDictionary;
公共示例类(){
//仅适用于示例#1
readonlyInnerDictionary=新的ReadOnlyDictionary(innerDictionary);
}   
公共IReadOnlyDictionary GetExampleOne(){
//需要第二个字典,它更简单,但返回的对象是真正的只读
返回readonlyInnerDictionary;
}
公共IReadOnlyDictionary GetExampleToo(){
//要求将InnerDictionary定义为Dictionary(不是IDictionary),但不要求定义第二个字典
//这是较少的锅炉板,但返回的对象可能会被重新转换为它的可变形式,这意味着它不是真正的突变安全。
返回内部字典;
}
公共ImmutableDictionary GetExampleTree(){
//返回了真正不可变的对象,但每次调用都会生成一个新实例;幸运的是,我所有的字典都很小(最多包含9个键)
返回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
        }
void CastingTest()
{
var dic1=新字典();
dic1.添加(“关键”、“价值”);
var dic2=新的只读字典(dic1);
var castedDic=(IDictionary)dic2;
castedDic.Add(“另一个键”、“另一个值”);//System.NotSupportedException,集合为只读
}
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.
        }
void AddTest()
{
var dic1=新字典();
dic1.添加(“关键”、“价值”);
var dic2=新的只读字典(dic1);
dic1.Add(“Key2”,“Value2”);//现在dic2也有2个值。
}

永远不要公开你的innerDictionary,你会没事的。

选择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
        }
void CastingTest()
{
var dic1=新字典();
dic1.添加(“关键”、“价值”);
var dic2=新的只读字典(dic1);
var castedDic=(IDictionary)dic2;
castedDic.Add(“另一个键”、“另一个值”);//System.NotSupportedException,集合为只读
}
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.
        }
void AddTest()
{
var dic1=新字典();
dic1.添加(“关键”、“价值”);
var dic2=新的只读字典(dic1);
dic1.Add(“Key2”,“Value2”);//现在dic2也有2个值。
}

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

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


这并不是最有效的解决方案,但在我的例子中,对于键数少于12的字典和表示状态的简单小对象,在大多数情况下这并不重要

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


这并不是最有效的解决方案,但在我的例子中,对于键数少于12的字典和表示状态的简单小对象,在大多数情况下这并不重要

@Syntax它解决了你的疑问吗?如果你愿意,我可以分享更多的细节。亚瑟,很抱歉耽搁了你,你的反馈对进一步讨论非常有帮助,但是在与朋友进一步讨论后,我找到了另一个我更喜欢的解决方案;对于任何感兴趣的人,我已经提供了它作为我自己问题的答案,并将其标记为已接受。没问题,但是,嗯,您从未指定要线程安全,即使如此,如果您从未公开DICT,ReadOnlyDictionary是线程安全的