我不知道这是否可行,但基本上,我希望公开类型为ReadOnlyCollection<ReadOnlyCollection<MyType>>
的属性,同时仍然能够修改暴露属性的类中的底层集合。此外,我希望我的类的用户能够保存对返回的集合的引用,以便在我在暴露属性的类内部更新它时更新它。
例如,如果这是一个集合,我可以这样做:
public class MyClass {
private List<MyType> _List;
public ReadOnlyCollection<MyType> RList {
get {
return _List.AsReadOnly();
}
}
}
通过执行_List.Add()
,仍然可以将项目添加到班级列表中。此外,如果这个班级的客户要做,请说:
var collectionRef = myClassInstance.RList;
当我从collectionRef
内部向列表中添加元素时,MyClass
也会发生变化。
如果我想要一个列表列表,就会出现问题:
private List<List<MyType>> _List;
public ReadOnlyCollection<ReadOnlyCollection<MyType>> RList {
get {
return _List.AsReadOnly();
}
}
上述尝试的直接问题是AsReadonly()
仅适用于外部列表。所以我会尝试返回一个ReadOnlyCollection<List<MyItem>>
,它不是属性的声明类型。我能想到满足声明的属性类型的唯一方法是以类似于:
ReadOnlyCollection
new ReadOnlyCollection<ReadOnlyCollection<MyItem>>(_List)
或
new ReadOnlyCollection<ReadOnlyCollection<MyItem>>() {
new ReadOnlyCollection<MyItem>(_List[0]),
new ReadOnlyCollection<MyItem>(_List[1]),
...
}
但是我不确定创建这个嵌套集合的语法是什么;此外,我不确定是否通过创建“新”集合,我将无法通过引用属性返回的值来跟踪对基础列表的更改。也就是说,如果我在MyClass
内_List[1].Add(myTypeInstance)
,我不确定持有只读版本的人会看到那个新项目。
我对所有其他方法持开放态度。基本上我只需要公开一个项目列表的列表,这些列表是只读的,但可以在公开属性的类中进行修改,并且客户端能够看到所反映的更改,而无需再从属性访问器中获取值。 / p>
答案 0 :(得分:0)
ReadOnlyCollection
无法做到这一点,至少不是这样。如果您向_List
添加新列表,则RList
的任何用户都需要有机会看到与该新列表相关联的新ReadOnlyCollection
。 ReadOnlyCollection
根本不支持。它只是 原始项目的只读视图,原始项目是可修改的。
您可以实现一个与ReadOnlyCollection
类似的自定义类,除了它不会返回原始项目,但包装它们。 ReadOnlyCollection
的实现很简单:几乎所有ReadOnlyCollection
方法都可以在一行中实现:它们要么抛出无条件异常(例如IList.Add
),返回一个常量值(例如IList.IsReadOnly
),或转发到代理容器(例如Count
)。
要使其适应您的使用需要进行的更改涉及直接处理项目的各种方法。请注意,这不仅仅是this[int]
索引器:您还需要确保相同列表的两个代理比较相等,并提供私有/内部方法以从代理获取原始列表,以使Contains
之类的方法。您还需要创建自定义枚举器类型,以确保GetEnumerator
不会开始返回原始项目。您需要创建自定义CopyTo
实现。但即使记住这些事情,也应该很容易做到。
也就是说,或许有一种不那么干净但更简单的方法:如果你创建一个源自MyReadOnlyCollection<T>
的自定义类ReadOnlyCollection<T>
,你可以提供一个内部Items
成员(转发致ReadOnlyCollection<T>
的受保护Items
成员。
然后,您可以创建MyReadOnlyCollection<MyReadOnlyCollection<MyClass>>
,并从您自己的程序集中调用RList[0].Items.Add
,而不必担心外部用户也可以调用它。
如上所述,如果外部列表实际上永远不会改变,那么它可以更简单:在这种情况下,您可以简单地执行类似
的操作public ReadOnlyCollection<ReadOnlyCollection<MyType>> RList {
get {
return _List.ConvertAll(list => list.AsReadOnly()).AsReadOnly();
}
}
无需监控_List
的更改。
答案 1 :(得分:-1)
使用Private Set
修改公开属性
private List<MyType> _List;
public ReadOnlyCollection<MyType> RList {
get {
return _List.AsReadOnly();
}
private set
{
_List = value;
}
}
使用Events通知其他类已修改集合
我在链接过期时添加代码。 :/
示例强>
The following simple example shows a class, ListWithChangedEvent, which is similar to the standard ArrayList class, but also invokes a Changed event whenever the contents of the list change. Such a general-purpose class could be used in numerous ways in a large
program.
// events1.cs
using System;
namespace MyCollections
{
using System.Collections;
// A delegate type for hooking up change notifications.
public delegate void ChangedEventHandler(object sender, EventArgs e);
// A class that works just like ArrayList, but sends event
// notifications whenever the list changes.
public class ListWithChangedEvent: ArrayList
{
// An event that clients can use to be notified whenever the
// elements of the list change.
public event ChangedEventHandler Changed;
// Invoke the Changed event; called whenever list changes
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}
// Override some of the methods that can change the list;
// invoke event after each
public override int Add(object value)
{
int i = base.Add(value);
OnChanged(EventArgs.Empty);
return i;
}
public override void Clear()
{
base.Clear();
OnChanged(EventArgs.Empty);
}
public override object this[int index]
{
set
{
base[index] = value;
OnChanged(EventArgs.Empty);
}
}
}
}
namespace TestEvents
{
using MyCollections;
class EventListener
{
private ListWithChangedEvent List;
public EventListener(ListWithChangedEvent list)
{
List = list;
// Add "ListChanged" to the Changed event on "List".
List.Changed += new ChangedEventHandler(ListChanged);
}
// This will be called whenever the list changes.
private void ListChanged(object sender, EventArgs e)
{
Console.WriteLine("This is called when the event fires.");
}
public void Detach()
{
// Detach the event and delete the list
List.Changed -= new ChangedEventHandler(ListChanged);
List = null;
}
}
class Test
{
// Test the ListWithChangedEvent class.
public static void Main()
{
// Create a new list.
ListWithChangedEvent list = new ListWithChangedEvent();
// Create a class that listens to the list's change event.
EventListener listener = new EventListener(list);
// Add and remove items from the list.
list.Add("item 1");
list.Clear();
listener.Detach();
}
}
}
<强>输出强>
This is called when the event fires.
This is called when the event fires.