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

7

我有一个类,用于枚举来自我的数据库的列表。 数据库中的所有表都有它们自己的类和属性,并且它们都派生自DatabaseTableRow。

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

我有一个User类,它派生自Page,而Page又派生自DatabaseTableRow。我还有一个属性,返回一个DatabaseLinkRowsEnumerator,即用户列表。
我还有一个UI函数,可以在水平列表中显示任何页面的列表,包括图像、名称和链接。
protected string GetVerticalListModuleHtml(IEnumerable<Page> pages)

我现在想做的就是将我拥有的DatabaseLinkRowsEnumerator的值传递给这个函数。User从Page派生而来,DatabaseLinkRowsEnumerator是一个IEnumerator。即使我尝试强制转换,我仍然会收到以下错误信息:

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

我正在使用ASP.NET 2.0。有没有什么方法可以在不制作每个完整副本的情况下进行强制转换/转换?

2个回答

13
使用.NET 2.0,这有点笨拙,但并不太难:
public static IEnumerable<TBase> Cast<TDerived, TBase>
    (IEnumerable<TDerived> source)
    where TDerived : TBase
{
    foreach (TDerived item in source)
    {
        yield return item;
    }
}

这样调用:

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

这将进行惰性评估。在LINQ中更容易 - 您可以使用Cast扩展方法:

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

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

如果继承关系设置正确,则此语句为真,但在OP的帖子中,我没有看到DatabaseTableRow和Page之间的关系。 - Justin Niessner
@Justin,OP说Page派生自DatabaseTableRow。 - Thomas Levesque
我有点困惑了...你会把这个方法放在哪里? - Connell
@Connell:无论如何 - 例如在实用程序类中。只需从需要该序列的任何位置调用它即可。 - Jon Skeet
@Connell:我忘记在方法中包含类型参数了,这可能没有帮助。我已经更新了该方法并提供了一个示例。 - Jon Skeet
啊,我试图聪明地将它放在DatabaseLinkRowsEnumerator类中。但这样做行不通,因为那不一定是。是的,我已经解决了类型问题,谢谢 :) - Connell

5

你可以这样做:

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

编辑:在.NET 2.0中,Cast扩展方法不可用。相反,您可以将Jon Skeet的实现作为普通静态方法使用。如果您正在使用VS2008,则还可以使用LinqBridge,这允许您在针对.NET 2.0时使用Linq到对象。


Enumerable.Cast<>()不是.NET 3.5中引入的LINQ方法吗? - adamjford

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接