【问题标题】:Return ReadOnlyCollection from IList<>从 IList<> 返回 ReadOnlyCollection
【发布时间】:2011-08-29 08:06:19
【问题描述】:

好的,所以 List 包含 AsReadOnly(),它为您提供 ReadOnlyCollection。我需要的是有一个 IList 类型的字段,以及一个会为此列表返回 ReadOnlyCollection 的属性。

示例类:

class Test
{
   private IList<Abc> list;

   public AddToList(Abc someItem) { /* adds inside the list */... }

   public ReadOnlyCollection<Abc> List { get { return ??? } } // <- no "set" here!
}

场景如下:当项目添加到列表中时,我需要在我的类中有一些自定义逻辑,并且我想通过调用 AddToList(someitem) 来限制添加到此列表,同时不允许使用列表.添加(一些项目)。问题是我使用 NHibernate,它需要 IList 接口,所以我不能在 IList 上转换/调用 AsReadOnly()(它不包含此方法)。

你会推荐什么方法来解决这种情况?我只需要一种方法让 NHibernate 以某种方式设置所需的集合,但我还需要限制用户。

【问题讨论】:

标签: c# .net nhibernate ilist readonly-collection


【解决方案1】:

你可以模仿AsReadOnly():

public ReadOnlyCollection<Abc> List
{
    get { return new ReadOnlyCollection<Abc>(list); }
}

更新
这不会创建list 的副本。 ReadOnlyCollection 不复制数据,它直接在提供的列表上工作。见documentation

只读集合只是一个带有防止修改集合的包装器的集合;因此,如果对基础集合进行了更改,只读集合会反映这些更改。
这个构造函数是一个 O(1) 操作。

【讨论】:

  • 这会创建一个遍历所有项目的新集合,还是保留对底层 innerCollection 的引用?
  • 它不会创建副本。这与AsReadOnly 中使用的代码完全相同。如果您不希望这种行为,您应该重新表述您的问题。
【解决方案2】:

试试

return new ReadOnlyCollection<Abc> (list);

【讨论】:

  • 好的,我也想过这个,但我更喜欢不将集合的内容复制到另一个集合的解决方案,这将在下面做到这一点,对吧?
  • 这将进行复制...只有当您创建一个实现 IList 接口的类并使用它时,才有可能实现不复制的解决方案...
  • @Yahia:错了。它不会创建副本
【解决方案3】:

使用以下方式,

public class Test
    {

        private IList<SubTest>      _subTests;


        public virtual void AddSubTest(SubTest SubTest)
        {
            if (_subTests == null)
                _subTests = new List<SubTest>();

            _subTests.Add(SubTest);

            return this;
        }


        public virtual IReadOnlyList<SubTest> SubTests
        {
            get
            {
                if (_subTests == null)
                    _subTests = new List<SubTest>();

                return _subTests.AsReadOnly();
            }
        }




        public void RemoveSubTest( SubTest SubTest )
        {
            if( _subTests == null ) 
                return;

            _subTests.Remove( SubTest );            
        }

    }

使用以下映射,它会将值设置为字段而不是只读列表的属性

<bag 
      name="SubTests" table="SubTest" lazy="true" access="field.camelcase-underscore"
      optimistic-lock="false"
      >
      <key column ="TestID" />
      <many-to-many class="SubTest, Domain" column="SubTestID" />
    </bag>

【讨论】:

    【解决方案4】:

    您也可以返回IEnumerable&lt;Abc&gt;,它是只读迭代器,并提供添加和删除元素的方法。

    【讨论】:

      【解决方案5】:

      在我看来,最好的方法是使用method suggested by Jon Skeet返回IEnumerable&lt;Abc&gt;

      public IEnumerable<Abc> Abcs {
          get { return list.Skip(0); }
      }
      

      如果您不担心消费者将IEnumerable&lt;T&gt; 转换回IList&lt;T&gt;,您可以返回IEnumerable&lt;T&gt;

      ReadOnlyCollection&lt;T&gt; 有一些严重的缺陷,主要是它实现了IList&lt;T&gt;,所以它确实有 Add 和 Remove 方法。如果消费者忽略检查其 ReadOnly 属性,这可能会导致运行时错误。我强烈建议不要使用它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-12
        相关资源
        最近更新 更多