以只读方式返回集合
我在一个multithreading环境中有一个对象来维护一组信息,例如:
public IList Data { get { return data; } }
我目前有return data;
由ReaderWriterLockSlim
包装,以保护集合免受共享冲突。 但是,为了更加确定,我想将集合作为只读方式返回,这样调用代码就无法对集合进行更改,只能查看已经存在的集合。 这是可能吗?
如果您的唯一目的是让调用代码不会出错,并且修改集合时应该只读取所有必要的是返回一个不支持Add,Remove等的接口。为什么不返回IEnumerable
? 调用代码必须进行转换,如果不知道他们正在访问的属性的内部,他们不太可能做。
但是,如果您的意图是阻止调用代码观察来自其他线程的更新,则必须回退到已经提到的解决方案,以根据您的需要执行深度或浅层复制。
如果基础数据存储为列表,则可以使用List(T).AsReadOnly方法。
如果可以枚举数据,则可以使用Enumerable.ToList方法将集合转换为List并在其上调用AsReadOnly。
我投票赞成你接受的答案并同意它 – 但是我可以给你一些考虑吗?
不要直接返回集合。 创建一个准确命名的业务逻辑类,以反映集合的目的。
这样做的主要优点在于您不能将代码添加到集合中,因此每当您在对象模型中拥有本机“集合”时,您总是会在整个项目中传播非OO支持代码来访问它。
例如,如果您的collections是发票,那么您的代码中可能有3个或4个位置,您可以在其中迭代未付款的发票。 你可以有一个getUnpaidInvoices方法。 然而,当你开始考虑像“payUnpaidInvoices(payer,account);”这样的方法时,真正的力量就会出现。
当您传递集合而不是编写对象模型时,您将永远不会发生整个重构类。
另请注意,这会使您的问题特别好。 如果您不希望人们更改集合,则您的容器不需要包含mutator。 如果您稍后决定在一个案例中实际上您必须修改它,您可以创建一个安全机制来执行此操作。
当你在本地集合中传递时,如何解决这个问题?
此外,无法使用额外数据增强本机集合。 下次当您发现将(Collection,Extra)传递给一个或两个以上的方法时,您会认识到这一点。 它表示“Extra”属于包含您的集合的对象。
我认为你在这里混淆概念。
ReadOnlyCollection
为现有集合提供只读包装器,允许您(A类)传递对集合安全的引用,因为调用者(B类)无法修改集合(即无法添加或删除任何元素)来自collections。)
绝对没有线程安全保证。
- 如果您(A类)在将其作为
ReadOnlyCollection
后继续修改基础集合,那么B类将看到这些更改,任何迭代器失效等等,并且通常对集合的任何常见并发问题持开放ReadOnlyCollection
。 - 此外,如果集合中的元素是可变的,则您(A类) 和调用者(B类)都将能够更改集合中对象的任何可变状态。
您的实施取决于您的需求: – 如果您不关心调用者(B类)看到对集合的任何进一步更改,那么您可以克隆集合,将其移出并停止关怀。 – 如果你肯定需要调用者(B类)来查看对集合所做的更改,并且你希望它是线程安全的,那么你手上就会遇到更多问题。 一种可能性是实现自己的线程安全的ReadOnlyCollection变体以允许锁定访问,但如果你想支持IEnumerable,这将是非平凡和非高效的,它仍然不会保护你免受可变元素的影响。采集。
应该注意到aku的答案只会保护列表为只读。 列表中的元素仍然非常可写。 在将它们放入只读列表之前,我不知道是否有任何保护非primefaces元素而不克隆它们的方法。
您可以使用该集合的副本。
public IList Data { get { return new List(data); }}
这样,它是否得到更新并不重要。
您想使用yield关键字。 循环遍历IEnumerable列表并使用yeild返回结果。 这允许消费者在不修改集合的情况下使用for。
它看起来像这样:
List _Data; public IEnumerable Data { get { foreach(string item in _Data) { return yield item; } } }