代码之家  ›  专栏  ›  技术社区  ›  alastairs

以只读方式返回集合

  •  17
  • alastairs  · 技术社区  · 17 年前

    public IList<string> Data 
    {
        get 
        {
            return data;
        }
    }
    

    我现在有 return data; ReaderWriterLockSlim 保护集合不受共享冲突的影响。但是,更确切地说,我希望以只读方式返回集合,这样调用代码就无法对集合进行更改,只能查看已经存在的内容。这有可能吗?

    7 回复  |  直到 13 年前
        1
  •  33
  •   aku    17 年前

    如果基础数据存储为列表,则可以使用 List(T).AsReadOnly
    如果可以枚举数据,则可以使用 Enumerable.ToList 方法将集合强制转换为列表并对其调用AsReadOnly。

        2
  •  19
  •   Sid M Vladimir Enchev    11 年前

    IEnumerable<string>

    但是,如果您的目的是防止调用代码观察来自其他线程的更新,那么您必须退回到前面提到的解决方案,根据需要执行深度或浅层复制。

        3
  •  19
  •   Sid M Vladimir Enchev    11 年前

    我投票赞成你的回答,同意这一点,但我能给你一些考虑吗?

    不要直接返回集合。创建一个准确命名的业务逻辑类,该类反映集合的目的。

    这样做的主要优点在于,您无法向集合添加代码,因此,每当您的对象模型中有一个本机“集合”时,您总是可以在整个项目中使用非OO支持代码来访问它。

    例如,如果您的集合是发票,那么代码中可能有3到4个地方可以迭代未付发票。您可以有一个getUnpaid方法。然而,当你开始考虑像“支付发票(付款人,账户)”这样的方法时,真正的力量就来了。

    当您传递集合而不是编写对象模型时,您将永远不会遇到整个重构类。

    还要注意的是,这让你的问题变得特别好。如果您不希望人们更改集合,那么您的容器不需要包含任何变体。如果您以后决定在一种情况下您实际上必须修改它,那么您可以创建一个安全的机制来进行修改。

        4
  •  11
  •   Daniel Fortunov    17 年前

    我认为你在这里混淆了概念。

    这个 ReadOnlyCollection 为现有集合提供只读包装,允许您(类a)在调用方(类B)无法修改集合(即不能)的情况下传递对集合安全的引用 添加 去除 集合中的任何元素。)

    • 如果您(A类)在将基础集合作为 只读集合 然后类B将看到这些更改,使任何迭代器失效,等等,并且通常会遇到集合的任何常见并发问题。
    • 此外,如果集合中的元素是可变的,则您(类A) 调用方(类B)将能够更改集合中对象的任何可变状态。

    -如果您不关心调用方(类B)看到集合的任何进一步更改,那么您可以克隆集合,分发它,然后停止关心。 -如果您确实需要调用方(类B)来查看对集合所做的更改,并且希望这是线程安全的,那么您将面临更多的问题。一种可能是实现您自己的ReadOnlyCollection线程安全变体,以允许锁定访问,但如果您想支持IEnumerable,这将是非常重要且不具性能的,并且 不会保护您免受集合中可变元素的影响。

        5
  •  3
  •   Community Mohan Dere    8 年前

    aku 的答案只会将列表保护为只读。列表中的元素仍然非常可写。我不知道在将非原子元素放入只读列表之前,是否有任何方法可以在不克隆它们的情况下保护它们。

        6
  •  3
  •   Charles Graham    17 年前

    你想使用 yield 关键词。在IEnumerable列表中循环,并使用yeild返回结果。这允许消费者使用for each,而无需修改集合。

    它看起来像这样:

    List<string> _Data;
    public IEnumerable<string> Data
    {
      get
      {
        foreach(string item in _Data)
        {
          return yield item;
        }
      }
    }
    
        7
  •  2
  •   Dror Helper    17 年前

    您可以改为使用集合的副本。

    public IList<string> Data {
    get {
        return new List<T>(data);
    }}
    

    这样一来,它是否得到更新并不重要。

    推荐文章