1

I have a class which must implement the following property

public ICollection<IType> Items { get { return this.items;} } 

My question is how to implement this when the type of this.items is a List<MyType> where MyType implements IType. I need to ensure the following:

  1. Unecessary enumeration of the list is avoided if possible
  2. That the class can internally treat the elements of this.items as their concrete type
  3. That external callers may add and remove elements to this collection

Thanks in advance.

6
  • 3
    Requirements (2) and (3) are contradictory. You don't know what concrete type the callers are going to add to the collection, so how can you internally treat them as one specific type? Commented Jun 21, 2012 at 17:50
  • 3
    Allowing external classes to add items is dangerous if you expect the items to be of a particular type -- you wouldn't want someone adding a dog to your collection of animals when you treat them all as cats :-) Commented Jun 21, 2012 at 17:50
  • @PaulPhillips - That is a good point. I may need to rethink how this is designed. Commented Jun 21, 2012 at 17:53
  • The big question is why are you trying to do this? Some context will lead to better and more appropriate responses. Commented Jun 21, 2012 at 17:53
  • Is this homework? If so, please add the tag. Commented Jun 21, 2012 at 17:53

5 Answers 5

1

How about Items being IEnumerable<IType>? IEnumerable is covariant so the code would just work with no changes. On the other hand, you could have another, dedicated method to add elements to the internal list.

class MainClass { public static void Main() { ShowMeHowToDoIt show = new ShowMeHowToDoIt(); show.Add( new TheType() ); foreach ( var item in show.Items ) { Console.WriteLine( item ); } } } public class ShowMeHowToDoIt { private List<TheType> items = new List<TheType>(); public void Add( TheType item ) { items.Add( item ); } public IEnumerable<IType> Items { get { return items; } } } public interface IType { } public class TheType : IType { } 
Sign up to request clarification or add additional context in comments.

Comments

1

Like Paul mentioned, you can't have both #2 and #3. You'll have to pick one or the other, or expose the concrete type to external callers. But, for your actual requirement, your best bet is to store your collection as a List internally, and just use a method when you need to get a member by the concrete type. Something like this:

private List<IType> items = new List<IType>(); private TType GetItem<TType>(int index) where TType : IType { return (TType)items[index]; } public ICollection<IType> Items { get { return this.items; } } 

Comments

1

As pointed out by @PaulPhillips in the comments to this question:

Requirements (2) and (3) are contradictory.

One approach is to change the type of Items to IEnumerable<IType> and have another property of ICollection<MyType>. This will mean some redesign but clearly I was going about this wrong anyway.

Thanks!

Comments

1

Either declare this.items as a List<IType> if you want to expose it as ICollection<IType> and thus allowing external callers to add ITypes that are not MyTypes.

Internally work like this on the items of the list

var myObj = this.items[i] as MyType; if (myObj == null) { work with this.items[i] and treat it as a IType } else { work with myObj which is a MyType } 

OR

declare the public property as

public ICollection<MyType> Items { get return this.items; } } 

and thus allow external callers to add only items of type MyType.

I am sorry, but you cannot fulfill conditions (2) and (3) at the same time


UPDATE

Another option is to only allow external callers to get items of the list but not to add items, by using an indexer having only a getter.

public IType this[int i] { get { return this.items[i]; } } 

an external caller can then access items like this

var obj = new ClassImplementingThisStuff(); int i = 5; IType x = obj[i]; 

Also add a count property

public int Count { get { return this items.Count; } } 

This solution avoids unnecessary enumeration.

Comments

0

I think the points in the comments about this being possibly a bad design are valid, however you can still do something like this and get away with it:

interface IFruit { string Name { get; } string SerialNumber { get; } } class Apple : IFruit { private string _serial = Guid.NewGuid().ToString(); public string Name { get { return "Apple"; } } public string SerialNumber { get { return _serial; } } } class AppleBasket : IEnumerable<IFruit> { private List<Apple> _items = new List<Apple>(); public void Add(Apple apple) { _items.Add(apple); } public IEnumerator<IFruit> GetEnumerator() { return _items.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return _items.GetEnumerator(); } } /******************/ AppleBasket basket = new AppleBasket(); Apple apple1 = new Apple(); basket.Add(apple1); Apple apple2 = new Apple(); basket.Add(apple2); foreach (IFruit fruit in basket) { Console.WriteLine(fruit.SerialNumber); } 

I would recommend you rethink your approach though.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.