【问题标题】:Is there a .NET collection interface that prevents adding objects?是否存在阻止添加对象的 .NET 集合接口?
【发布时间】:2010-07-22 04:36:44
【问题描述】:

我有一个类维护另一个类的对象列表。对象列表是公共属性。我想阻止用户直接添加和删除对象到这样的列表中:

      MyObject.MyListProperty.Add(object);

相反,我希望他们使用将在内部进行一些处理然后将对象添加到列表的方法。

我有一些想法:

  • 创建List<T> 的后代并覆盖添加和删除
  • 通过属性getter返回新的list副本(list比较短,不超过30个对象)

是否有一些收藏界面没有添加和删除?

编辑:
我将选择ReadOnlyCollection<T>。原因是包装的集合可以更新,并且更改将立即在只读对象中可见(请参阅 ReadOnlyCollection<T>AsReadOnly() 的 MSDN 代码示例)。这允许只读列表只创建一次。

IEnumerable 的问题是对象可以被转换回原来的List<T> 然后 直接操作。

【问题讨论】:

  • 我也在找这个+1

标签: c# .net collections list


【解决方案1】:

您可以使用ReadOnlyCollection - 将您的收藏包装在此并将ReadOnlyCollection 返回给您班级的用户:

return new ReadOnlyCollection(innerCollection);

或者使用List<T>类的AsReadOnly方法:

return innerCollection.AsReadOnly();

IEnumerable 接口将满足您的需求,因为它只有一个成员 GetEnumerator(),它只会让您迭代项目。

【讨论】:

  • IReadOnlyCollection<T>AsReadOnly 仅接受 IList<T>ICollection<T> 也有解决方案吗?
【解决方案2】:

您最简单的选择是通过公共属性将您的列表公开为以下IEnumerableICollectionReadOnlyCollection 之一。

因此,您可以创建自己的 type 列表,将您的 Items 公开为上述列表之一,但具有用于添加的内部方法,例如

public class MyList<MyType>
{
    private List<MyType> items;

    public MyList()
    {
        items = new List<MyType>();
    }

    public IEnumerable Items { get { return items.AsEnumerable(); } }
    public Add(MyType item)
    {
        // do internal processing
        items.Add(item);
    }
}

【讨论】:

  • 请注意,这不会阻止将集合转换回 List 并在其上调用 Add。如果您确实需要防止添加,则 ReadOnlyCollection 是您的选择。此外,没有必要调用 items.AsEnumerable 并且我认为这不会像编写的那样编译,因为 AsEnumerable() 将返回 IEnumerable 并且 Items 的类型为 IEnumerable。
  • @Jamie IEnumerable&lt;MyType&gt; 继承自 IEnumerable,所以它会编译,但我同意它们应该返回 IEnumerable,并且 AsEnumerable 是多余的。
  • @Jamie,它会编译,但是,我同意演员表是可能的。这只是一个示例,展示了用户可以做什么,正如我之前在帖子中提到的那样,ReadOnlyCollection is 是一个选项。干杯。
【解决方案3】:

也许AsReadOnly 方法可以解决问题,将只读实例交给公众。

否则,IEnumerable&lt;T&gt; 没有Add 也没有Remove,所以你可以这样做:

private List<int> _myList;
public IEnumerable<int> MyList
{
   get
   {
      return this._myList.ToList();
   }
}

我宁愿选择IEnumerable&lt;T&gt;(+ 副本)作为ReadOnlyCollection&lt;T&gt;,因为:对您的基本列表(您的只读集合是从中创建的)的更改将立即显示在您的读取实例中- 仅收集。这可能会导致锁定和 straange 问题:)

【讨论】:

  • 为什么是return this._myList.ToList(); 而不是return this._myList;
  • IList&lt;int&gt;ToArray 怎么样?两全其美,不是吗?
  • IList 有一个 Add 方法,因此列表不会是只读的,并且您可以更改数组的内容(这不会影响此类,因为数组是副本)。解决OP问题的唯一接口是IEnumerable
  • 我不是数组的粉丝...不知道为什么...如果您再修改一下我的示例,您可以拥有真正的迭代器传递实现,这会更好而不是创建另一个对象(数组)来迭代元素!
  • @Rob Fonseca-Ensor:简单:分发一份副本,而不是同一个参考。调用者我将其转换为列表,并且可以修改您的内部数据存储!
【解决方案4】:

开箱即用,只有 IEnumerable&lt;T&gt; 将提供此功能,而不会暴露任何可能诱使客户端获取运行时异常的 AddRemove 公共方法。

如果您希望您的公共 API 明确声明该集合是只读的并且您需要一个索引器,则您必须围绕现有的 List&lt;T&gt;T[] 编写自己的包装器。

【讨论】:

  • IEnumerable&lt;T&gt; 虽然不支持随机访问
【解决方案5】:

你可以只给他们一个对象,它总是返回一个他们可以用来访问结构的枚举器吗?

【讨论】:

    【解决方案6】:

    并不能真正回答您的问题,但如果您决定实施您的两个想法之一,这是有用的信息: 您可以使用 ToArray 创建一个副本并返回一个数组。

    或者你可以这样做: http://en.csharp-online.net/CSharp_Generics_Recipes%E2%80%94Making_Read-Only_Collections_the_Generic_Way

    【讨论】:

      【解决方案7】:

      ICollection(非泛型版本)只有 IEnumerable + Count

      【讨论】:

        猜你喜欢
        • 2013-02-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多