【问题标题】:IList<IList<T>> to IReadonlyCollection<IReadonlyCollection<T>>IList<IList<T>> 到 IReadonlyCollection<IReadonlyCollection<T>>
【发布时间】:2017-06-10 21:17:27
【问题描述】:

我有一个字符串数组列表,我想将这两个集合设为只读。

所以我有这个代码:

public XmlPatternTree(IList<string> nodeNames, IList<IList<string>> attributeNames,
        IList<IList<string>> attributeValues) : this()
    {
        NodeNames = new ReadOnlyCollection<string>(nodeNames);
        AttributeNames = new ReadOnlyCollection<ReadOnlyCollection<string>>();
        AttributeValues = attributeValues;
        Depth = NodeNames.Count;
    }

我的问题是 AttributeNames 和 AttributeValues 分配导致编译错误,看来我可以从非只读对象的非只读集合创建 ReadonlyCollection 的 ReadonlyCollection。

除了遍历所有值并将它们添加到列表中之外,我还能做些什么吗?

谢谢

【问题讨论】:

    标签: c# .net c#-4.0 readonly readonly-collection


    【解决方案1】:

    如果您将类型从 IList&lt;string&gt; 更改为 List&lt;string&gt;,那么应该可以:

    attributeNames.Select((x) => x.AsReadOnly()).ToList().AsReadOnly();
    

    如果您无法修改您的方法签名(即您保留IList&lt;string&gt;),那么您可以这样做:

    attributeNames.Select((x) => x.ToList().AsReadOnly()).ToList().AsReadOnly();
    

    【讨论】:

      【解决方案2】:

      如果 .net 框架的版本高于 4.0,则 List&lt;&gt; 的通用版本实现 IReadOnlyCollection&lt;&gt; 接口。 如果对您更方便,您可以将签名从IList&lt;ILIst&lt;&gt;&gt; 更改为List&lt;List&lt;&gt;&gt;,应该可以正常工作。

       AttributeNames = attributeNames;
       AttributeValues = attributeValues;
      

      【讨论】:

        【解决方案3】:

        只需注意IReadOnlyList&lt;out T&gt; 类型的协方差(类似于 vasil oreshenski 的回答)。

        如果您决定拥有:

        public XmlPatternTree(IReadOnlyList<string> nodeNames, 
          IReadOnlyList<IReadOnlyList<string>> attributeNames,
          IReadOnlyList<IReadOnlyList<string>> attributeValues) : this()
        {
          NodeNames = nodeNames;
          AttributeNames = attributeNames;
          AttributeValues = attributeValues;
        }
        
        public IReadOnlyList<string> NodeNames { get; private set; }
        public IReadOnlyList<IReadOnlyList<string>> AttributeNames  { get; private set; }
        public IReadOnlyList<IReadOnlyList<string>> AttributeValues { get; private set; }
        public int Depth => NodeNames.Count;
        

        在你的类中,那么提到的协方差意味着你可以使用引用转换,而不是在另一个类中进行任何包装,如下所示:

        var nn = new List<string>();
        var an = new List<string[]>();
        var av = new List<string[]>();
        // populate 'nn', 'an', and 'av'
        
        // the following compiles with no wrapper class:
        var tree = new XmlPatternTree(nn, an, av);
        

        当然,人们可以将接口转换回实际类型,例如List&lt;string[]&gt;,并且如果他们猜测该类型确实是数组列表,则无需使用反射即可修改集合。但是,那将是非常恶性的,因此您可以假设只有“好”的人使用您的课程是没有问题的

        PS!我在上面用IReadOnlyList&lt;out T&gt; 所说和编码的内容也可以用IReadOnlyCollection&lt;out T&gt; 完成,因为它也是协变的(“out”)。您只是没有属性的索引器访问权限(例如var name = tree.AttrbuteNames[idx1][idx2])。但是你可以使用HashSet&lt;&gt; 和类似的不是IReadOnlyList&lt;&gt;

        【讨论】:

          猜你喜欢
          • 2013-06-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多