Home All Groups Group Topic Archive Search About

Casting IEnumerable<T> to IEnumerable<V>

Author
30 Jun 2006 11:57 AM
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.

Author
30 Jun 2006 12:54 PM
Barry Kelly
"Daniel" <dfi***@gmail.com> wrote:

> 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

Author
30 Jun 2006 5:57 PM
Joanna Carter [TeamB]
"Daniel" <dfi***@gmail.com> a écrit dans le message de news:
1151668651.537391.11***@d56g2000cwd.googlegroups.com...

Show quote
| 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

--
Joanna Carter [TeamB]
Consultant Software Engineer
Author
30 Jun 2006 7:40 PM
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
Author
30 Jun 2006 9:10 PM
Joanna Carter [TeamB]
"Daniel" <dfi***@gmail.com> a écrit dans le message de news:
1151696433.820867.289***@b68g2000cwa.googlegroups.com...

| 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

--
Joanna Carter [TeamB]
Consultant Software Engineer
Author
1 Jul 2006 8:38 PM
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<T>

Show quote
> | 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

AddThis Social Bookmark Button