Reputation: 3532
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:
this.items
as their concrete typeThanks in advance.
Upvotes: 1
Views: 120
Reputation: 112324
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.
Upvotes: 1
Reputation: 48230
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 { }
Upvotes: 1
Reputation: 16651
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.
Upvotes: 0
Reputation: 3532
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!
Upvotes: 1
Reputation: 3302
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;
}
}
Upvotes: 1