只读列表列表 c#
Read only list of lists c#
一般来说,我正在制作的程序涉及存储少量可以分类的条目(在任何给定时间可能少于 30 个)。我想让这些条目可见,但不能从 class 外部使用它们进行更改。我制作了一个名为 Entry 的 class,它可以被修改,另一个名为 ReadOnlyEntry,它是一个 Entry 对象的包装器。组织这些 Entry 对象的最简单方法似乎是创建一个 List<List<Entry>>
,其中每个 List<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.
列表中的最后一项将公开为 public。第一个让我更改条目,第二个让我添加或删除条目,第三个让我添加或删除类别。每当数据发生变化时,我都必须保持这些包装器的准确性。这对我来说似乎很复杂,所以我想知道是否有明显更好的方法来处理这个问题。
编辑 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);
}
您可以使用 List<T>.AsReadOnly()
到 return ReadOnlyCollection<T>
。
此外,您正在折磨 List<T>
class 以您的方式存储数据。构建您自己的 classes 层次结构,用于存储您的个人列表。
您可以为 Entry
创建一个仅包含 getter 的接口;您将通过此接口公开元素以提供只读访问权限:
public interface IEntry
{
int Value { get; }
}
可写的实现很简单:
public sealed class Entry : IEntry
{
public int Value { get; set; }
}
现在您可以利用 return 一个 List<List<Entry>>
作为一个 IReadOnlyCollection<IReadOnlyCollection<IEntry>>
的事实,而无需做任何额外的工作:
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;
}
注意 Data
属性 的实现是多么简单。
如果您需要向 IEntry
添加新属性,您还必须将它们添加到 Entry
,但您不需要更改 Database
class.
如果您使用的是 C#5 或更早版本,Data
将如下所示:
public IReadOnlyCollection<IReadOnlyCollection<IEntry>> Data
{
get { return _list; }
}
.NET
集合 应该 支持 covariance, but they don't support it themselves (instead some interfaces support covariance https://msdn.microsoft.com/ru-ru/library/dd233059.aspx)。协方差意味着如果 Concrete
是 Base
的子类,则 List<Conctrete>
的行为类似于 List<Base>
的子类。您可以使用接口协变,也可以像这样使用转换:
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)
{
}
}
}
感谢 Matthew Watson 指出我之前答案版本中的错误。
一般来说,我正在制作的程序涉及存储少量可以分类的条目(在任何给定时间可能少于 30 个)。我想让这些条目可见,但不能从 class 外部使用它们进行更改。我制作了一个名为 Entry 的 class,它可以被修改,另一个名为 ReadOnlyEntry,它是一个 Entry 对象的包装器。组织这些 Entry 对象的最简单方法似乎是创建一个 List<List<Entry>>
,其中每个 List<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.
列表中的最后一项将公开为 public。第一个让我更改条目,第二个让我添加或删除条目,第三个让我添加或删除类别。每当数据发生变化时,我都必须保持这些包装器的准确性。这对我来说似乎很复杂,所以我想知道是否有明显更好的方法来处理这个问题。
编辑 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);
}
您可以使用 List<T>.AsReadOnly()
到 return ReadOnlyCollection<T>
。
此外,您正在折磨 List<T>
class 以您的方式存储数据。构建您自己的 classes 层次结构,用于存储您的个人列表。
您可以为 Entry
创建一个仅包含 getter 的接口;您将通过此接口公开元素以提供只读访问权限:
public interface IEntry
{
int Value { get; }
}
可写的实现很简单:
public sealed class Entry : IEntry
{
public int Value { get; set; }
}
现在您可以利用 return 一个 List<List<Entry>>
作为一个 IReadOnlyCollection<IReadOnlyCollection<IEntry>>
的事实,而无需做任何额外的工作:
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;
}
注意 Data
属性 的实现是多么简单。
如果您需要向 IEntry
添加新属性,您还必须将它们添加到 Entry
,但您不需要更改 Database
class.
如果您使用的是 C#5 或更早版本,Data
将如下所示:
public IReadOnlyCollection<IReadOnlyCollection<IEntry>> Data
{
get { return _list; }
}
.NET
集合 应该 支持 covariance, but they don't support it themselves (instead some interfaces support covariance https://msdn.microsoft.com/ru-ru/library/dd233059.aspx)。协方差意味着如果 Concrete
是 Base
的子类,则 List<Conctrete>
的行为类似于 List<Base>
的子类。您可以使用接口协变,也可以像这样使用转换:
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)
{
}
}
}
感谢 Matthew Watson 指出我之前答案版本中的错误。