469,271 Members | 1,759 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,271 developers. It's quick & easy.

List<T> inheritance

Hi all, I have a classic problem: List<Tand List<Xwhere X is a class X :
T.
Ok, I know the problem: I cannot cast List<Ton List<Xbecause also if X
is a T, List<Xis not a List<T>.
What I don't know is the solution :)

Let's see this scenario (that obviously doesn't compile):

// --------------------------
class BaseClass
{ }

class DerivedClass : BaseClass
{ }

class BaseClassCollection : List<BaseClass>
{ }

class DerivedClassCollection : List<DerivedClass>
{ }

class Collector
{
BaseClassCollection _classes = new BaseClassCollection();
public virtual BaseClassCollection Classes
{
get { return _classes; }
}
}

class DerivedCollector : Collector
{
public override DerivedClassCollection Classes
{
get { return _classes; }
}
}
// --------------------------

This is what I would have: more specific classes that work on base classes.
What is the more similar solution?

Thanks!
Nov 23 '06 #1
22 9651
Typically this is solved with a generic method, e.g.

void SomeMethod(List<Tdata) where T : SomeBase {

}

Now you can pass either a List<SomeBaseor a List<SomethingElseas long as
SomethingElse : SomeBase. Note that in most cases you don't need to specify
the T when calling - i.e.

List<SomethingElsedata = //
SomeMethod(data); // or could use longer SomeMethod<SomethingElse>(data);

Marc
Nov 23 '06 #2
Shouldn't it be:

void SomeMethod<T>(List<Tdata) where T: SomeBase {
}

?

Christof

"Marc Gravell" <ma**********@gmail.comschrieb im Newsbeitrag
news:uf**************@TK2MSFTNGP04.phx.gbl...
Typically this is solved with a generic method, e.g.

void SomeMethod(List<Tdata) where T : SomeBase {

}

Now you can pass either a List<SomeBaseor a List<SomethingElseas long
as SomethingElse : SomeBase. Note that in most cases you don't need to
specify the T when calling - i.e.

List<SomethingElsedata = //
SomeMethod(data); // or could use longer SomeMethod<SomethingElse>(data);

Marc

Nov 23 '06 #3
D'oh! yup ta - I missed a <T>, but in my head I typed it perfectly ;-p
The dangers of coding in notepad and hitting "Send"...

"what he said"

Marc
Nov 23 '06 #4
"Marc Gravell" <ma**********@gmail.comha scritto nel messaggio
news:uf**************@TK2MSFTNGP04.phx.gbl...
Typically this is solved with a generic method, e.g.

void SomeMethod(List<Tdata) where T : SomeBase {

}

Now you can pass either a List<SomeBaseor a List<SomethingElseas long
as SomethingElse : SomeBase. Note that in most cases you don't need to
specify the T when calling - i.e.

List<SomethingElsedata = //
SomeMethod(data); // or could use longer SomeMethod<SomethingElse>(data);
mmm... it's interesting, I didn't know this possibility, but I don't
understand how this can be applied to my scenario ;)
where I need to cast a CollectionOfItems to a CollectionOfDerivedItems.

I think the only solution is to use the List<T>.ConvertAll<X>() or
something...

Nov 23 '06 #5
Well, the subject and bit at the top of you post (List<Tand List<X>, with
X : T) is unrelated to the bit at the bottom of your post (BaseCollection
and DerivedCollection, with DerivedCollection : BaseCollection).

The difference is very significant; the first has the contained type in an
inheritance chain, the second has the container in an inheritance chain. I
answered the top 2. Re the latter, you can't change the type in a virtual.
You could, however, have a generic base class which you then inherit from
(which gets us back closer to List<T>), and add methods. You will, however,
run into sever problems trying to work with situations in which the
container type *and* the contained type change. The answer here, then, is
usually to use an interface; for instance

public interface ICollector<Twhere T : BaseClass {// or something
T Classes {get;}
}

then you can use generic methods typed to ICollector<T>, and it doesn't
matter what the inheritance is between collectors (or not at all) as long as
they all meet the interface.

Marc
Nov 23 '06 #6
Addditional note: a derived collector can redeclare ("new") methods, or it
can override them; I don't think it can do both at once, and if the original
method is tied to an interface, then anybody using that interface will still
get the old method, not the redeclared one. Likewise anybody using a
variable typed as the base-collection.

Personally I would try to avoid this scenario; maybe have unrelated
collections as necessary - inheritance here is going to make for huge
complexity. Of course, it may be warranted, but I couldn't possibly say
without more info.

Marc
Nov 23 '06 #7
"Marc Gravell" <ma**********@gmail.comschrieb im Newsbeitrag
news:uw**************@TK2MSFTNGP04.phx.gbl...
Addditional note: a derived collector can redeclare ("new") methods, or it
can override them; I don't think it can do both at once, and if the
original method is tied to an interface, then anybody using that interface
will still get the old method, not the redeclared one.
But you can reimplement that method of the interface. Then calling the
method on the interface will call the new implementation if the value is of
the derived type. But you can't call the baseimplementation of that method
from the new implementation, like one often does in overriding methods.
Nov 23 '06 #8
"Marc Gravell" <ma**********@gmail.comha scritto nel messaggio news:%
Well, the subject and bit at the top of you post (List<Tand List<X>,
with X : T) is unrelated to the bit at the bottom of your post
(BaseCollection and DerivedCollection, with DerivedCollection :
BaseCollection).
I never said that DerivedCollection : BaseCollection.
Just the items collected are respectively X and T, where X : T.

Nov 23 '06 #9
"Marc Gravell" <ma**********@gmail.comha scritto nel messaggio
news:uw**************@TK2MSFTNGP04.phx.gbl...
Personally I would try to avoid this scenario; maybe have unrelated
collections as necessary - inheritance here is going to make for huge
complexity.
yes, also because it doesn't compile :)

I try to explain.
Let's say I have these base classes:

class Item {}

class ItemCollection : List<Item{}

class Document
{
ItemCollection Items;
}
and the derived ones:

class Word : Item {}

class WordCollection : List<Word{}
// just to have the Word properties righ
// out of the box, without unboxing each accessed item.

class Letter : Document
{
WordCollection Words;
// or an overriden WordCollection Items;
}

Right now the best solution I've found is

class Letter : Document
{
public WordCollection Words
{
get
{
WordCollection words = new WordCollection ();
foreach (Item item in Items)
{
if (item is Word)
{
words.Add((Word)di);
}
}
return words;
}
}
}

but I'm thinking about abolish the WordCollection and return a Word[].

Thanks
Nov 23 '06 #10
I think the mistake you may be making here is dealing in concrete types too
much.

If all the caller needs to know is that it is an enumerable set of Thing
classes, then just return IEnumerable<Thing>. If it needs to know that it is
a list, then return IList<Thing>; that way, the question of List<Thing>
versus ThingCollection versus Thing[] just disappears, as all three
implement IList<Thing>

In your example, sure the answer here is again generics... e.g. Word : Item,
and ItemCollection<Twhere T : Item, then Document has
"ItemCollection<WordWords"...?

Marc
Nov 23 '06 #11
"Marc Gravell" <ma**********@gmail.comha scritto nel messaggio
news:%2****************@TK2MSFTNGP02.phx.gbl...
If all the caller needs to know is that it is an enumerable set of Thing
classes, then just return IEnumerable<Thing>. If it needs to know that it
is a list, then return IList<Thing>; that way, the question of List<Thing>
versus ThingCollection versus Thing[] just disappears, as all three
implement IList<Thing>
mmm... not so clear but...
In your example, sure the answer here is again generics... e.g. Word :
Item, and ItemCollection<Twhere T : Item, then Document has
"ItemCollection<WordWords"...?
This can be the right solution :)

class Item {}

class Document
{
List<ItemItems;
}
and the derived ones:

class Word : Item {}

class WordCollection : List<Twhere T : Word {}

class Letter : Document
{
WordCollection Words;
}

it will compile this?
I'll try ;)

Nov 23 '06 #12
"Fabio" <zn*******@virgilio.ita écrit dans le message de news:
uW**************@TK2MSFTNGP02.phx.gbl...

| class WordCollection : List<Twhere T : Word {}

This is a redundant declaration, you might as well just do :

class Letter : Document
{
List<Wordwords;
}

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer
Nov 23 '06 #13
"Joanna Carter [TeamB]" <jo****@not.for.spamha scritto nel messaggio
news:%2****************@TK2MSFTNGP06.phx.gbl...
| class WordCollection : List<Twhere T : Word {}

This is a redundant declaration, you might as well just do :

class Letter : Document
{
List<Wordwords;
}
Yes, but I don't want to expose a List<T>.

Nov 23 '06 #14
Hello!

I wouldn't call it redundant, but it could be implemented differently:

class ItemCollection<T: IList<Twhere T : Item
class WordCollection : ItemCollection<Word{}

Would allow him to have generic methods with the following signature
pattern:

public void ProcessCollection<T>(ItemCollection<Targ) where T : Item
{
// use methods defined on types ItemCollection and Item
}

From what I can read from the discussion, the original poster (Fabio Z)
wants to provide a set of concrete (potentially sealed) classes that are
exposed from the API to the client application. Exposing types of type T
(i.e. List<Tis flexible and easy, but not necessarily what you want to
do).

I've used the above pattern when I had a generic inheritance chain, and it
worked really well.

--
With regards
Anders Borum / SphereWorks
Microsoft Certified Professional (.NET MCP)
Nov 23 '06 #15
"Fabio" <zn*******@virgilio.ita écrit dans le message de news:
ee**************@TK2MSFTNGP04.phx.gbl...

| Yes, but I don't want to expose a List<T>.

You're not, you would be using a List<Wordas an internal field, then you
can expose the list however you like. My point is that deriving from a
generic list class just to strictly type it really is a waste of effort,
unless you want to create a constrained derivative like others have
suggested.

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer
Nov 23 '06 #16
"Anders Borum" <an****@sphereworks.dkha scritto nel messaggio
class ItemCollection<T: IList<Twhere T : Item
This doesn't compile: "Error 1 Constraints are not allowed on non-generic
declarations"
Nov 24 '06 #17
That works just fine for me as long as it meets the interface and Item is
well-defined; to get the error message you report I need to use:

class ItemCollection : IList<Twhere T : Item

So check you haven't lost a <Tsomewhere

Marc
Nov 24 '06 #18
Fabio, let us know if you found the solution (or got the code snippet I
provided to compile).

--
With regards
Anders Borum / SphereWorks
Microsoft Certified Professional (.NET MCP)
Nov 24 '06 #19
"Anders Borum" <an****@sphereworks.dkha scritto nel messaggio
news:ex**************@TK2MSFTNGP04.phx.gbl...
Fabio, let us know if you found the solution (or got the code snippet I
provided to compile).
I'm sorry, now I tell you :)

In my last post I thinked you erroneously used IList<Tinstead of List<T>
and this is why I told that it didn't compile: I used List<T>

I tryed your solution but not tested, because implementing IList<TI would
implement manually a dozen of methods, and avoid this is a reason for what I
used inheritance.

If I should say it all, I should implement an interface, but not IList<T>,
because I need a object that doesn't publish Add, Remove, Clear that are
managed internally (I'm thinking about IEnumerable<T>).

Right now, I'm using the solution I told in my post of 23-nov at 17:17

Thanks

Nov 27 '06 #20
"Fabio Z" <zn*******@virgilio.ita écrit dans le message de news:
O8**************@TK2MSFTNGP03.phx.gbl...

| If I should say it all, I should implement an interface, but not IList<T>,
| because I need a object that doesn't publish Add, Remove, Clear that are
| managed internally (I'm thinking about IEnumerable<T>).

If you don't want to publish those methods, then look at ICollection, the
non-generic interface. All the methods you want to hide are those that
belong to ICollection<Tso, by using the non-generic interface, you should
get what you need.

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer
Nov 27 '06 #21

"Joanna Carter [TeamB]" <jo****@not.for.spamha scritto nel messaggio
news:e2**************@TK2MSFTNGP03.phx.gbl...

If you don't want to publish those methods, then look at ICollection, the
non-generic interface. All the methods you want to hide are those that
belong to ICollection<Tso, by using the non-generic interface, you
should
get what you need.
You're right, but I'll loose the strong-typing :(
Nov 27 '06 #22
"Fabio" <zn*******@virgilio.ita écrit dans le message de news:
eE**************@TK2MSFTNGP03.phx.gbl...

| You're right, but I'll loose the strong-typing :(

Since ICollection doesn't expose any members that access the items in the
list, this is very "strongly typed" :-)

You are allowed to write your own interfaces you know :-) So, why don't you
derive your own interface from ICollection ?

Something like :

public IReadOnlyCollection<T: ICollection
{
T this[int index] { get; set; }
}

Then you get to write a class that implements this interface like this :

public class ItemCollection<T: IReadOnlyCollection<Twhere T : Item
{
...
}

This will then also have to implement IEnumerable by inheritance.

Does this help ?

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer
Nov 27 '06 #23

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

14 posts views Thread by Dave | last post: by
2 posts views Thread by Brian Pelton | last post: by
reply views Thread by Iron Moped | last post: by
7 posts views Thread by Andrew Robinson | last post: by
35 posts views Thread by Lee Crabtree | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by suresh191 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.