Casting IEnumerable<T> to IEnumerable<V>

D

Daniel

Suppose a collection class defined as:

public class Friends: ReadOnlyCollection<Friend> {}

where Friend implements IPerson:

public class Friend:IPerson {}

My question: is there a neat+lean way to implement IEnumerable<Person>
in the collection class?:

public class Friends: ReadOnlyCollection<Friend>, IEnumerable<Person>
{

public new IEnumerator<Person> GetEnumerator()
{
// ******* CAST DOES NOT WORK **********
return (IEnumerator < IVSelItem >) base.GetEnumerator();
}
}


Any suggestions?
Thanks in advance.
 
B

Barry Kelly

Daniel said:
Suppose a collection class defined as:

public class Friends: ReadOnlyCollection<Friend> {}

where Friend implements IPerson:

public class Friend:IPerson {}

My question: is there a neat+lean way to implement IEnumerable<Person>
in the collection class?:

Neat and lean? Not totally. Covariance is required here, and it isn't
supported by C#. The best you can do is this (which is neat, but not
100% lean):

---8<---
static IEnumerable<T> Cast<T>(IEnumerable source)
{
foreach (object item in source)
yield return (T) item;
}
--->8---

-- Barry
 
J

Joanna Carter [TeamB]

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

| Suppose a collection class defined as:
|
| public class Friends: ReadOnlyCollection<Friend> {}
|
| where Friend implements IPerson:
|
| public class Friend:IPerson {}
|
| My question: is there a neat+lean way to implement IEnumerable<Person>
| in the collection class?:
|
| public class Friends: ReadOnlyCollection<Friend>, IEnumerable<Person>
| {
|
| public new IEnumerator<Person> GetEnumerator()
| {
| // ******* CAST DOES NOT WORK **********
| return (IEnumerator < IVSelItem >) base.GetEnumerator();
| }
| }

Does this help ?

public interface IPerson
{
}

public class Friend : IPerson
{
}

public class Friends : List<Friend>, IEnumerable<IPerson>
{
public new IEnumerator<IPerson> GetEnumerator()
{
foreach (Friend friend in (this as IEnumerable<Friend>))
yield return friend as IPerson;
}
}

....used like this :

{
Friends friends = new Friends();

friends.Add(new Friend());
friends.Add(new Friend());
friends.Add(new Friend());

ReadOnlyCollection<Friend> roFriends = new ReadOnlyCollection<friends>;

foreach (IPerson person in roFriends)
... ;
}

....although this would also work with the same code :

{
Friends friends = new List<Friend>();

friends.Add(new Friend());
friends.Add(new Friend());
friends.Add(new Friend());

ReadOnlyCollection<Friend> roFriends = new ReadOnlyCollection<friends>;

foreach (IPerson person in roFriends)
... ;
}

I think you are making things overly complicated :)

Joanna
 
D

Daniel

Thanks !

It works ! but I think yielding the elements will be more expensive
than using System.Collections.IEnumerator and casting to IPerson, from
a performance standpoint.

Joanna:

yes, it seems overcomplicated the way I presented it, but maybe is
because I reduced the complexity just to show the issue... Let me
explain more:

I have several collections like Friends: Men (collection of
Man:IPerson), Women (collection of Woman:IPerson), Artists (collection
of Artist:IPerson), and so on; all of them derive from
ReadOnlyCollection<T>

Now I need these collections to show certain behavior and present
themselves thorough an interfase named IGroupOfPeople, like:

interfase IGroupOfPeople: IEnumerable<IPerson>
{
void SayHi();
int AverageHeight {get;}
}

now, the collections will implement the interfase IGroupOfPeople, and
therefore they must provide the GetEnumerator<IPerson>.

Maybe is better to modify the interfase to :

interfase IGroupOfPeople: System.Collections.IEnumerable
{
void SayHi();
int AverageHeight {get;}
}

And let the users of the collection the casting from System.Object to
IPerson.

I hope I could explain myself.

Thanks
Daniel
 
J

Joanna Carter [TeamB]

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

| Thanks !
|
| It works ! but I think yielding the elements will be more expensive
| than using System.Collections.IEnumerator and casting to IPerson, from
| a performance standpoint.

As I showed in the second example, you don't even need to write a separate
enumerator, you can just do a foreach on a List<Friend> asking for the
element as IPerson and it will work.

| I have several collections like Friends: Men (collection of
| Man:IPerson), Women (collection of Woman:IPerson), Artists (collection
| of Artist:IPerson), and so on; all of them derive from
| ReadOnlyCollection<T>


Why are you deriving from ReadOnlyCollection<T> ? It is only a read-only
wrapper class that has to take a list that implements IList<T>. Unless you
are planning on adding extra list functionality, there really is no need to
derive from generic list classes; all you need is usually in the class as it
stands.

| Now I need these collections to show certain behavior and present
| themselves thorough an interfase named IGroupOfPeople, like:
|
| interfase IGroupOfPeople: IEnumerable<IPerson>
| {
| void SayHi();
| int AverageHeight {get;}
| }
|
| now, the collections will implement the interfase IGroupOfPeople, and
| therefore they must provide the GetEnumerator<IPerson>.

This is bad design. You should keep the IEnumerable behaviour separate from
any "group" behaviour.

| Maybe is better to modify the interfase to :
|
| interfase IGroupOfPeople: System.Collections.IEnumerable
| {
| void SayHi();
| int AverageHeight {get;}
| }
|
| And let the users of the collection the casting from System.Object to
| IPerson.

Not a good idea; this is just what generic classes seek to eliminate.

Joanna
 
D

Daniel

| I have several collections like Friends: Men (collection of
| Man:IPerson), Women (collection of Woman:IPerson), Artists (collection
| of Artist:IPerson), and so on; all of them derive from
| ReadOnlyCollection<T>


Why are you deriving from ReadOnlyCollection<T> ? It is only a read-only
wrapper class that has to take a list that implements IList<T>. Unless you
are planning on adding extra list functionality, there really is no need to
derive from generic list classes; all you need is usually in the class as it
stands.

Deriving from ReadOnlyCollection was based on the prospective use of
the collections: they populate themselves (from the data tier) and
should be ReadOnly fpr their consumers, that's the reason for using the
wrapper instead of IList said:
| Now I need these collections to show certain behavior and present
| themselves thorough an interfase named IGroupOfPeople, like:
|
| interfase IGroupOfPeople: IEnumerable<IPerson>
| {
| void SayHi();
| int AverageHeight {get;}
| }
|
| now, the collections will implement the interfase IGroupOfPeople, and
| therefore they must provide the GetEnumerator<IPerson>.

This is bad design. You should keep the IEnumerable behaviour separate from
any "group" behaviour.
I don't understand where is the "badness": consumers accessing objects
that implement IGroupOfPeople will be only interested in enumerating
its members (IPersons), I thought that the cleanest way is to just
expose the IEnumerable<IPerson> interfase, is there a better way?

Daniel
 

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