Connell
Connell

Reputation: 14411

Casting IEnumerable<Derived> to IEnumerable<BaseClass>

I have a class which I use to enumerate through lists from my database. All tables in the database have their own class with their own properties, and they all derive from DatabaseTableRow.

public class DatabaseLinkRowsEnumerator<T> : IEnumerator<T>, IEnumerable<T> where T : DatabaseTableRow

I have a User class, which derives from Page, which derives from DatabaseTableRow. I then have a property that returns a DatabaseLinkRowsEnumerator, a list of users.

I also have a UI function that displays lists of any Page in a horizontal list, with the image, name and a link.

protected string GetVerticalListModuleHtml(IEnumerable<Page> pages)

Now all I want to do is pass the value I have of DatabaseLinkRowsEnumerator to this function. User derives from Page, and DatabaseLinkRowsEnumerator is an IEnumerator. Even when I try to cast, I get the following error:

Unable to cast object of type 'Database.DatabaseLinkRowsEnumerator`1[Database.User]' to type 'System.Collections.Generic.IEnumerable`1[Database.Page]'.

I'm using ASP.NET 2.0. Does anyone have any ideas of how to cast/convert this without making an entire copy of each?

Upvotes: 7

Views: 5768

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1502066

Using .NET 2.0, it's slightly awkward, but not too hard:

public static IEnumerable<TBase> Cast<TDerived, TBase>
    (IEnumerable<TDerived> source)
    where TDerived : TBase
{
    foreach (TDerived item in source)
    {
        yield return item;
    }
}

Call it like this:

IEnumerable<Page> pages = UtilityClass.Cast<User, Page>(users);

This will evaluate it lazily. In LINQ it's easier - you use the Cast extension method:

var baseSequence = derivedSequence.Cast<BaseClass>();

In .NET 4, IEnumerable<T> is covariant in T so there's a reference type conversion from IEnumerable<DerivedClass> to IEnumerable<BaseClass> already :)

Upvotes: 13

Thomas Levesque
Thomas Levesque

Reputation: 292555

You can do that:

DatabaseLinkRowsEnumerator<User> users = ...
IEnumerable<Page> = users.Cast<Page>();

EDIT: the Cast extension method is not available in .NET 2.0. You can use Jon Skeet's implementation as a normal static method instead. If you're using VS2008, you can also use LinqBridge, which allows you to use Linq to Objects when targeting .NET 2.0

Upvotes: 5

Related Questions