Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
只读列表c#_C#_Covariance_Readonly Collection - Fatal编程技术网

只读列表c#

只读列表c#,c#,covariance,readonly-collection,C#,Covariance,Readonly Collection,一般来说,我制作的程序需要存储少量可分类的条目(在任何给定时间可能少于30条)。我想让这些条目在使用它们的类之外被看到,但不被修改。我创建了一个名为Entry的类,它可以修改,另一个名为ReadOnlyEntry,它是Entry对象的包装器。组织这些条目对象的最简单方法似乎是创建一个列表,其中每个列表都是一个类别。但随后,以只读方式公开这些数据变得混乱和复杂。我意识到我必须拥有以下每种类型的一个对象: List<List<Entry>> data; List<Lis

一般来说,我制作的程序需要存储少量可分类的条目(在任何给定时间可能少于30条)。我想让这些条目在使用它们的类之外被看到,但不被修改。我创建了一个名为Entry的类,它可以修改,另一个名为ReadOnlyEntry,它是Entry对象的包装器。组织这些条目对象的最简单方法似乎是创建一个
列表
,其中每个
列表
都是一个类别。但随后,以只读方式公开这些数据变得混乱和复杂。我意识到我必须拥有以下每种类型的一个对象:

List<List<Entry>> data;
List<List<ReadOnlyEntry>>  //  Where each ReadOnlyEntry is a wrapper for the Entry in the same list and at the same index as its Entry object.
List<IReadOnlyCollection<ReadOnlyEntry>>  //  Where each IReadOnlyCollection is a wrapper for the List<ReadOnlyEntry> at the same index in data.
IReadOnlyCollection<IReadOnlyCollection<ReadOnlyList>> readOnlyList  //  Which is a wrapper for the first item I listed.
列表数据;
列表//其中每个ReadOnlyEntry都是同一列表中的条目的包装器,其索引与其条目对象相同。
列表//其中每个IReadOnlyCollection都是数据中相同索引处列表的包装器。
IReadOnlyCollection readOnlyList//是我列出的第一项的包装。
列表中的最后一项将作为公共项公开。第一个允许我更改条目,第二个允许我添加或删除条目,第三个允许我添加或删除类别。每当数据发生变化时,我必须保持这些包装的准确性。这对我来说似乎很复杂,所以我想知道是否有更好的方法来处理这个问题

编辑1: 为了澄清这一点,我知道如何使用List.asReadOnly(),我建议上面做的事情将解决我的问题。我只是想听听更好的解决办法。让我给你一些代码

class Database
{
    //  Everything I described above takes place here.

    //  The data will be readable by this property:
    public IReadOnlyCollection<IReadOnlyCollection<ReadOnlyList>> Data
    {
        get
        {
            return readOnlyList;
        }
    }

    //  These methods will be used to modify the data.
    public void AddEntry(stuff);
    public void DeleteEntry(index);
    public void MoveEntry(to another category);
    public void AddCategory(stuff);
    public void DeleteCategory(index);
}
类数据库
{
//我上面描述的一切都发生在这里。
//此属性将读取数据:
公共IReadOnlyCollection数据
{
得到
{
返回只读列表;
}
}
//这些方法将用于修改数据。
公开作废补遗(stuff);
公共分录(索引);
公共条目(另一类别);
公共物品类别(物品);
公共服务类别(索引);
}
您可以使用
List.AsReadOnly()
返回
ReadOnlyCollection


此外,您正在折磨以您现在的方式存储数据的
列表
类。构建您自己的类层次结构,存储您的单个列表。

您可以为只包含getter的
条目创建一个接口;您可以通过此接口公开元素以提供只读访问:

public interface IEntry
{
    int Value { get; }
}
可写实现将简单地包括:

public sealed class Entry : IEntry
{
    public int Value { get; set; }
}
现在,您可以利用这样一个事实:您可以将
列表作为
IReadOnlyCollection
返回,而无需做任何额外的工作:

public sealed class Database
{
    private readonly List<List<Entry>> _list = new List<List<Entry>>();

    public Database()
    {
        // Create your list of lists.

        List<Entry> innerList = new List<Entry>
        {
            new Entry {Value = 1},
            new Entry {Value = 2}
        };

        _list.Add(innerList);
    }

    public IReadOnlyCollection<IReadOnlyCollection<IEntry>> Data => _list;
}

.NET
collections应该支持,但它们本身不支持它(相反,一些接口支持协方差)。协方差意味着
List
的行为类似于
List
的子类,如果
Concrete
Base
的子类。您可以使用接口协变量,也可以像这样使用转换:

public IReadOnlyCollection<IReadOnlyCollection<IEntry>> Data
{
    get { return _list; }
}
using System.Collections.Generic;

namespace MyApp
{
    interface IEntry
    {
    }

    class Entry : IEntry
    {
    }

    class Program
    {
        private List<List<Entry>> _matrix = null;

        public List<List<IEntry>> MatrixWithROElements
        {
            get 
            {
                return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry));
            }
        }

        public IReadOnlyList<List<IEntry>> MatrixWithRONumberOfRows
        {
            get 
            {
                return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry));
            }
        }

        public List<IReadOnlyList<IEntry>> MatrixWithRONumberOfColumns
        {
            get 
            {
                return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry) as IReadOnlyList<IEntry>);
            }
        }

        public IReadOnlyList<IReadOnlyList<IEntry>> MatrixWithRONumberOfRowsAndColumns
        {
            get 
            {
                return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry));
            }
        }

        public void Main(string[] args)
        {    
        }
    }
}
使用System.Collections.Generic;
名称空间MyApp
{
界面熵
{
}
课程名称:IEntry
{
}
班级计划
{
私有列表_矩阵=null;
带元素的公共列表矩阵
{
得到
{
返回_matrix.ConvertAll(row=>row.ConvertAll(item=>item as IEntry));
}
}
公共IREADONLILIST矩阵,带RonofRows数
{
得到
{
返回_matrix.ConvertAll(row=>row.ConvertAll(item=>item as IEntry));
}
}
带有列编号的公共列表矩阵
{
得到
{
返回_matrix.ConvertAll(row=>row.ConvertAll(item=>item as IEntry)作为IReadOnlyList);
}
}
公共IReadOnlyList矩阵,带RonNumber of RowsandColumns
{
得到
{
返回_matrix.ConvertAll(row=>row.ConvertAll(item=>item as IEntry));
}
}
公共void Main(字符串[]参数)
{    
}
}
}

感谢Matthew Watson指出了我上一个答案版本中的错误。

我正在使用List.asReadOnly(),但返回ReadOnlyCollection仍然允许用户修改集合中的对象。我考虑过创建额外的类来表示一个类别,但得出的结论是,这样做不值得,因为类别中唯一的东西就是条目列表。我可能只是有一个列表,而不是为它做一个类。我在编写类时看到的唯一好处是它使语法变得更简单。这里有许多好的设计原则可以应用,等等。如果它看起来很复杂,那么这就清楚地表明您需要将它分解为多个类。这是OO编程的基本原因之一。
List
在这种情况下不是协变的。行
公共列表矩阵WithRoelements=>\u矩阵
不会编译。具体来说,
列表
类型没有定义为
列表
,因此它在
T
上不协变。你们两个绝对正确。这是最明智的做法。我完全忘记了接口的协方差。谢谢你的帮助!我已将此标记为最佳答案。是的!这是一个优秀的接口应用程序。我知道我错过了什么!