将IEnumerable <Derived>转换为IEnumerable <BaseClass>

Con*_*ell 4 c# generics inheritance casting .net-2.0

我有一个类,我用它来枚举我的数据库中的列表.数据库中的所有表都有自己的类,它们都有自己的属性,它们都来自DatabaseTableRow.

public class DatabaseLinkRowsEnumerator<T> : IEnumerator<T>, IEnumerable<T> where T : DatabaseTableRow
Run Code Online (Sandbox Code Playgroud)

我有一个User类,它派生自Page,它派生自DatabaseTableRow.然后我有一个属性返回DatabaseLinkRowsEnumerator,一个用户列表.

我还有一个UI功能,可以显示水平列表中任何页面的列表,包括图像,名称和链接.

protected string GetVerticalListModuleHtml(IEnumerable<Page> pages)
Run Code Online (Sandbox Code Playgroud)

现在我想要做的就是将DatabaseLinkRowsEnumerator的值传递给这个函数.用户派生自Page,DatabaseLinkRowsEnumerator是IEnumerator.即使我尝试施放,我也会收到以下错误:

Unable to cast object of type 'Database.DatabaseLinkRowsEnumerator`1[Database.User]' to type 'System.Collections.Generic.IEnumerable`1[Database.Page]'.
Run Code Online (Sandbox Code Playgroud)

我正在使用ASP.NET 2.0.有没有人有任何想法如何投射/转换这个没有制作每个的完整副本?

Jon*_*eet 12

使用.NET 2.0,它有点尴尬,但不是太难:

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

像这样称呼它:

IEnumerable<Page> pages = UtilityClass.Cast<User, Page>(users);
Run Code Online (Sandbox Code Playgroud)

这将懒洋洋地评估它.在LINQ中,它更容易 - 您使用Cast扩展方法:

var baseSequence = derivedSequence.Cast<BaseClass>();
Run Code Online (Sandbox Code Playgroud)

在.NET 4中,IEnumerable<T>是协变的T所以有一个引用类型转换IEnumerable<DerivedClass>IEnumerable<BaseClass>已经:)


Tho*_*que 5

你可以这样做:

DatabaseLinkRowsEnumerator<User> users = ...
IEnumerable<Page> = users.Cast<Page>();
Run Code Online (Sandbox Code Playgroud)

编辑:Cast扩展方法在 .NET 2.0 中不可用。您可以将 Jon Skeet 的实现用作普通的静态方法。如果您使用的是 VS2008,您还可以使用LinqBridge,它允许您在面向 .NET 2.0 时使用 Linq to Objects