2

I would like to pass an array-like or set-like structure where other classes append to it, but are never allowed to remove from it.

Is there a built-in data structure in C# that manages this?

neverendingqs
  • 4,006
  • 3
  • 29
  • 57
  • How will you add to it? – elyashiv Jan 26 '16 at 18:07
  • you probably need simple array. and you can resize it when ever you want. `Array.Resize` – M.kazem Akhgary Jan 26 '16 at 18:07
  • @M.kazemAkhgary Why would you do that yourself when you could just encapsulate one of the existing data structures that is going to manage that for you, and most likely much more efficiently (and with a lower probability of error) than your custom implementation would. – Servy Jan 26 '16 at 18:53

4 Answers4

1

No, you have to build your own interface based on one of the existing implementations.

Ivan G.
  • 5,027
  • 2
  • 37
  • 65
1

Is there a built-in data structure in C# that only allows items to be added, but not removed?

No, there isn't.

But there is one that easily allows you to create your own - Collection<T> class which can be found inside the System.Collections.ObjectModel namespace.

public class Collection<T> : IList<T>, ICollection<T>, IEnumerable<T>, 
    IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>

All you need is to create a derived class, override a few methods and throw NotSupportedException like this

public class AddOnlyCollection<T> : System.Collections.ObjectModel.Collection<T>
{
    protected override void ClearItems() { throw new NotSupportedException(); }
    protected override void RemoveItem(int index) { throw new NotSupportedException(); }
    protected override void SetItem(int index, T item) { throw new NotSupportedException(); }
}

UPDATE: As correctly mentioned in the comments by Tseng, the above is not considered a good practice, so a better approach would be to define your own interface and use the above just for easy implementing it, like this

public interface IAddOnlyCollection<T> : IReadOnlyCollection<T> // could be IReadOnlyList<T> if you wish
{
    void Add(T item);
}

public class AddOnlyCollection<T> :
    System.Collections.ObjectModel.Collection<T>, IAddOnlyCollection<T>
{
    // Same as above
}

UPDATE 2: It turns out that the class ReadOnlyCollection<T> from the same namespace is even a better choice. All you need is to inherit it and define Add method. No interface is needed in that case.

So the full final solution looks like this

public class AddOnlyCollection<T> : ReadOnlyCollection<T>, ICollection<T>
{
    public void Add(T item) { Items.Add(item); }
}
Community
  • 1
  • 1
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • 1
    It's bad practice throwing a `NotSupportedException` on abstract classes and interfaces and should be avoided unless you are are absolutely forced to use the `Collection` type (i.e. framework restrictions), brings unexpected results when used in code that expects a collection to be properly implement these methods. Better implement your own interface. – Tseng Jan 26 '16 at 19:20
  • @Tseng I agree. But it's already broken by core interfaces like `ICollection` and `IList`. But yeah, OP can easily create own interface, so the above will just easy the implementation. – Ivan Stoev Jan 26 '16 at 19:24
  • @Tseng Anyway, good point! Thank you, updated the answer taking it into consideration. Bad practices should be avoided :) – Ivan Stoev Jan 26 '16 at 19:39
  • I think `IReadOnlyCollection` and implementation classes are for collections that don't mutate after creation. I created an example @ http://pasted.co/a6485c2b and it throws exceptions. – neverendingqs Jan 28 '16 at 16:15
  • @neverendingqs Your test is incorrect because you use `IList`. The idea is to use `AddOnlyCollection` in the calls. In your example, replace the first line with `var test = new AddOnlyCollection();' – Ivan Stoev Jan 28 '16 at 16:20
  • But `ReadOnlyCollection` implements `IList. Isn't that a concern? – neverendingqs Jan 28 '16 at 16:25
  • @neverendingqs Yes, it does. And `List` implements `IReadOnlyCollection`, but is not read only. Quite messy, I agree. Anyway, I've updated (for the N-th time:-) the answer, now even your example with `IList` will work. – Ivan Stoev Jan 28 '16 at 16:30
  • @neverendingqs To conclude, all the posted answers to your OP question are simply "no, there isn't such built-in data structure - you need to create your own". From that point, everything is arbitrary - you can use any of the techniques presented or build it from scratch (implementing just the fully supported interfaces) on top of a private `List` field. To be honest, the code will not be too much compared to inherit approaches. – Ivan Stoev Jan 28 '16 at 16:45
0

You can create your own class that implements IList. See this answer for details:

How do I override List<T>'s Add method in C#?.

You can't just inherit from List and override Remove because Remove is not virtual. But your own class could have a private List variable that you use to track your items. You have to implement Remove if you do this, but your Remove method could just throw a NotSupportedException.

Community
  • 1
  • 1
GendoIkari
  • 11,734
  • 6
  • 62
  • 104
0

You have to build your own class, and you can make use of following :

  1. Array.AsReadOnly() method.
  2. ReadOnlyCollection.
AnjumSKhan
  • 9,647
  • 1
  • 26
  • 38