只读列表<字典<>>

Posted

技术标签:

【中文标题】只读列表<字典<>>【英文标题】:Readonly List<Dictionary<>> 【发布时间】:2015-09-23 21:10:51 【问题描述】:

如果我们有字段List&lt;Dictionary&lt;&gt;&gt;,如何将其公开为只读属性?

举例:

public class Test

    private List<Dictionary<string, object>> _list;

我可以这样暴露它

public ReadOnlyCollection<Dictionary<string, object>> List

    get  return _list.AsReadOnly(); 

但仍然可以更改目录:

var test = new Test();
test.List[0]["a"] = 3; // possible
test.List[0].Add("e", 33); // possible

这里尝试将其设为只读

public ReadOnlyCollection<ReadOnlyDictionary<string, object>> List

    get
    
        return _list.Select(item =>
            new ReadOnlyDictionary<string, object>(item)).ToList().AsReadOnly();
    

我认为这种方法的问题很明显:它是一个新字典列表。

我想要的是类似于List<>.AsReadOnly() 的东西,让属性充当_list 的包装器。

【问题讨论】:

@oppassum:这似乎是一个不同的问题。这里的这个问题是关于如何确保只读列表的 elements 也是只读的(至少根据它们的公共接口)。 是的,评论已删除。实际上,我只是没有仔细查看代码。 【参考方案1】:

如果您无法创建 Dictionary 对象的新列表,我建议直接从您的班级公开您需要的项目:

public IReadOnlyDictionary<string, object> this[int i] 

    get  return this._list[i]; 

//OR
public IReadOnlyDictionary<string, object> GetListItem(int i)

    return _list[i];


public int ListCount

    get  return this._list.Count; 
  

然后像这样使用它:

var test = new Test();

var dictionary = test[0];
//OR
dictionary = test.GetListItem(0);

int count = test.ListCount;

【讨论】:

索引器,酷!另一件事(我在我的问题中错过了)是 Dictionary&lt;&gt; 实现 IReadOnlyDictionary&lt;&gt;,所以我不需要创建 new 项(不确定 ReadOnlyDictionary 构造函数实际上做了什么,也许是一样)。 @Sinatr 标准 System.Collections.Generic.Dictionary 在 .NET 4.5 及更高版本中实现 IReadOnlyDictionary。您使用的是旧版本的 .NET 吗? msdn.microsoft.com/en-us/library/hh136548(v=vs.110).aspx 我使用的是 4.5。仅出于这个原因,我已经投票了。不知道如何使用给定的方法(晚上,我的头不再工作了),明天会检查它。我喜欢索引器的想法,但它隐藏列表。必须暴露Count,不能使用foreach...【参考方案2】:

我创建了一个ReadOnlyDictionary 列表并用转换后的字典填充它,完成后我将整个列表转换为AsReadOnly

代码:

public ReadOnlyCollection<ReadOnlyDictionary<string, object>> AsReadOnlyListAndElements

    get
    
        var list = _list.Select(elem => new ReadOnlyDictionary<string, object>(elem));
        return list.ToList().AsReadOnly();
    

旧解决方案:

您可以使用要公开的方法创建与此类似的包装器:

public class ReadOnlyDict<K, V>

    private Dictionary<K, V> dictionary;

    public ReadOnlyDict(Dictionary<K, V> dict)
    
        dictionary = dict;
    

    public V this[K key]
    
        get
        
            return dictionary[key];
        
    

    // Add more methods per your request

还有一个扩展方法:

namespace System.Collections.Generic

    public static class DictionaryExt
    
        public static ReadOnlyDict<K, V> ToReadOnlyDictionary<K, V>(this Dictionary<K, V> dict)
        
            return new ReadOnlyDict<K, V>(dict);
        
    

你的代码看起来像这样:

Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("2", "2");
dict.Add("3", "3");

var roDict = dict.ToReadOnlyDictionary();
var a = roDict["2"];

【讨论】:

我没有测试过,但你确定这会阻止 test.List[0]["3"] = "4"; @Blam 是的,因为索引器上没有设置器。 对于字典列表,我必须为列表中的每个项目调用ToReadOnlyDictionary(),对吗?为什么不按照@Blam 解决方案简单地将Dictionary 转换为IReadOnlyDictionary?我没有看到(或根本不明白)这个答案的意义。 Orel,你能展示一下我的财产List 的样子吗? 我有一个问题 - 不是解决方案。 @Sinatr - 假设 dics 是一个字典列表,你可以这样做:dics.Select(dic =&gt; dic.ToReadOnlyDictionary()).ToList();。如果需要,您也可以将列表转换为只读。【参考方案3】:

没有办法避免创建新列表,因为必须将Dictionary 项目转换为IReadOnlyDicionary(通过使用CastSelect)。那么问题来了

为什么它应该是一个列表?

ReadOnlyList 仅用于通过索引或foreach 访问项目。那么,为什么不简单地提供呢?

带有索引器的@Bas 解决方案和带有yield return 的简单属性产生最终解决方案:

public class Test

    private List<Dictionary<string, object>> _list = new List<Dictionary<string, object>>();

    public IEnumerable<IReadOnlyDictionary<string, object>> Items
    
        get
        
            foreach (var item in _list)
                yield return item;
        
    

    public IReadOnlyDictionary<string, object> this[int i]
    
        get  return _list[i]; 
    

    public int Count
    
        get  return _list.Count; 
    

字典(和列表)可以从外部以只读方式访问,如下所示:

var test = new Test();
Console.WriteLine(test[0]["a"]); // direct access
foreach (var item in test.Items) // enumeration
    foreach(var dic in item)
        Console.WriteLine(dic);

【讨论】:

以上是关于只读列表<字典<>>的主要内容,如果未能解决你的问题,请参考以下文章

字典操作2

在 C# 中对字典列表进行分组

python中的数据类型之元组和字典

列表中的c#字典[重复]

字典值中的排序列表[重复]

字典列表仅保留最后一行