473,385 Members | 1,409 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

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 9851
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
by: Dave | last post by:
Hello all, After perusing the Standard, I believe it is true to say that once you insert an element into a std::list<>, its location in memory never changes. This makes a std::list<> ideal for...
4
by: matty.hall | last post by:
I have two classes: a base class (BaseClass) and a class deriving from it (DerivedClass). I have a List<DerivedClass> that for various reasons needs to be of that type, and not a List<BaseClass>....
2
by: Brian Pelton | last post by:
I am not sure how to fix this problem I've stumbled into... I have a list<> of an interface type. I need to pass that list to a method that adds more objects to the list. But, eventually, I...
3
by: Varangian | last post by:
Hello, there I have a problem with regards to System.Collections.Generic.List<T> I need to pass a class with implements an interface - TestClass : IPerson I put this class in a...
9
by: Paul | last post by:
Hi, I feel I'm going around circles on this one and would appreciate some other points of view. From a design / encapsulation point of view, what's the best practise for returning a private...
0
by: Iron Moped | last post by:
I'm airing frustration here, but why does LinkedList<not support the same sort and search methods as List<>? I want a container that does not support random access, allows forward and reverse...
7
by: Andrew Robinson | last post by:
I have a method that needs to return either a Dictionary<k,vor a List<v> depending on input parameters and options to the method. 1. Is there any way to convert from a dictionary to a list...
56
by: Zytan | last post by:
Obviously you can't just use a simple for loop, since you may skip over elements. You could modify the loop counter each time an element is deleted. But, the loop ending condition must be...
45
by: Zytan | last post by:
This returns the following error: "Cannot modify the return value of 'System.Collections.Generic.List<MyStruct>.this' because it is not a variable" and I have no idea why! Do lists return copies...
35
by: Lee Crabtree | last post by:
This seems inconsistent and more than a little bizarre. Array.Clear sets all elements of the array to their default values (0, null, whatever), whereas List<>.Clear removes all items from the...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.