Generics, Collections, Casting

A

anders.forsgren

This is a common problem with generics, but I hope someone has found
the best way of solving it.

I have these classes: "Fruit" which is a baseclass, and "Apple" which
is derived. Further I have an "AppleBasket" which is a class that
contains a collection of apples. So, some code:

class Fruit{
}

class Apple : Fruit
{
}

abstract class FruitBasket
{
public void ListFruit()
{
foreach(Fruit fruit in Fruits)
Debug.WriteLine("Hello fruit : "+fruit);
}

abstract ICollection<Fruit> Fruits{ get; }
}

class AppleBasket : FruitBasket
{
// Don't want a <Fruit> collecion here.
private ICollection<Apple> apples;

public ICollection<Fruit> Fruits
{
get{ return apples; } // Can't do this!
}
}


The obvious way is to have a private collection of "Fruit" in the
applebasket, but if I'm doing loads of handling in the Applebasket that
is specific to apples, then I cant do that without casting each fruit
to apple all the time. Not something you want to do *only* because you
have to return the collection as a collection of fruit in one single
property. That would mean that generics really worked to make the code
uglier rather than better.

Also, I cant cast the ICollection<Apple> to ICollection<Fruit> since
they aren't inherited from eachother. Note that the 'AppleBasket' class
in this example isnt supposed to be though of as a collection class or
anything that itself should be generic, like Basket<Apple>, It's just
an unfortunate circumstance of the example...

So how to how to resolve this? any suggestions are welcome...
thanks
 
H

Helge Jensen

class AppleBasket : FruitBasket
{
// Don't want a <Fruit> collecion here.
private ICollection<Apple> apples;

public ICollection<Fruit> Fruits
{
get{ return apples; } // Can't do this!
}
}
So how to how to resolve this? any suggestions are welcome...
thanks

Use a casting adapter for ICollection<Apple> to ICollection<Fruit> and
return that:

Something along the lines of:

public class AppleBasket: FruitBasket {
public ICollection<Apple> Apples; // any impl of ICollection<Apple>
public ICollection<Fruit> Fruits
{ get { return new UpcasetedCollection<Apple, Fruit>(Apples); } }
...
}

public class UpcastedCollection<T, R> : ICollection<R> where T : R
{
public readonly ICollection<T> Parent;
public UpcastedCollection(ICollection<T> parent)
{ this.Parent = parent; }
public void Add(R r) { Parent.Add((T)r); }
public void Clear() { Parent.Clear(); }
public bool Contains(R r)
{ return r is T && Parent.Contains((T)r); }
public void CopyTo(R[] rs, int index)
{ foreach (T t in Parent) rs[index++] = t; }
public bool Remove(R r) { return r is T && Parent.Remove((T)r); }
public int Count { get { return Parent.Count; } }
public bool IsReadOnly { get { return Parent.IsReadOnly; } }
public IEnumerator<R> GetEnumerator()
{ foreach (T t in Parent) yield return t; }
System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{ return GetEnumerator(); }
}
 
W

Ward Bekker

Hi Anders,

Nice Issue, struggled with that one as well. You can use List<Apple>. A
list implements the non-generic Ilist, so you can cast it to that to
loop through the fruit. You cannot cast List<Apple> to List<Fruit>,
because List<Apple> does not derive from List<Fruit>.

--
Ward Bekker
"Asp.Net Discussions for the Professional Developer"
http://www.dotnettaxi.com

"Free .Net 2.0 C# to/from VB.Net Code Converter"
http://www.dotnettaxi.com/Tools/Converter.aspx
 
S

Stoitcho Goutsev \(100\)

Andreas,

If you use generics for your basked I don't see why you need to use
inheritance. Generics my cause problems, but most of the times the problems
comes from rather incorected design.

If you want to use generics from your basked just do:

class FruitBasket<T>
{
private List<T> fruits = new List<T>();
public void ListFruit()
{
foreach (T fruit in Fruits)
Console.WriteLine("Hello fruit : " + fruit);
}

public ICollection<T> Fruits
{
get
{
return fruits;
}
}

}

When you want to create an apple basked then:

FruitBasket<Apple> appleBasket = new FruitBasket<Apple>()

At the very end this what the generics are all about.

The downside ofcourse is that FruitBasket<Apple> and FruitBasket<Orange>
doesn't have common base class, but if you are going for that you don't need
generics.
 
K

Kevin Spencer

I've tested the following successfully:

abstract class FruitBasket<T> where T : Fruit
{
public void ListFruit()
{
}

public abstract ICollection<T> Fruits { get; }
}

class AppleBasket : FruitBasket<Apple>
{
private ICollection<Apple> apples;

public override ICollection<Apple> Fruits
{
get { return apples; }
}
}

--
HTH,

Kevin Spencer
Microsoft MVP
Professional Numbskull

Show me your certification without works,
and I'll show my certification
*by* my works.
 
J

Joanna Carter [TeamB]

<[email protected]> a écrit dans le message de (e-mail address removed)...

| I have these classes: "Fruit" which is a baseclass, and "Apple" which
| is derived. Further I have an "AppleBasket" which is a class that
| contains a collection of apples.

| The obvious way is to have a private collection of "Fruit" in the
| applebasket, but if I'm doing loads of handling in the Applebasket that
| is specific to apples, then I cant do that without casting each fruit
| to apple all the time. Not something you want to do *only* because you
| have to return the collection as a collection of fruit in one single
| property. That would mean that generics really worked to make the code
| uglier rather than better.
|
| Also, I cant cast the ICollection<Apple> to ICollection<Fruit> since
| they aren't inherited from eachother. Note that the 'AppleBasket' class
| in this example isnt supposed to be though of as a collection class or
| anything that itself should be generic, like Basket<Apple>, It's just
| an unfortunate circumstance of the example...
|
| So how to how to resolve this? any suggestions are welcome...

Try the following :

class Fruit
{
}

class Apple : Fruit
{
}

abstract class Basket<fruitT> where fruitT : Fruit
{
public void ListFruit()
{
foreach (fruitT fruit in fruits)
Console.WriteLine("Hello fruit : " + fruit);
}

private IList<fruitT> fruits = new List<fruitT>();

public IList<fruitT> Fruits
{
get { return fruits; }
}
}

class AppleBasket : Basket<Apple>
{

}

Joanna
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top