使用LINQ选择通用列表中的元素并转换为其特定类型

时间:2011-10-06 14:11:31

标签: linq

我有一个名为NodeUpgrade的基类,它有几种子类型。特定子类的示例是FactoryUpgrade

我有一个NodeUpgrades列表,它可以是不同子类型的混合。如何编写linq查询以检索NodeUpgrade类型并转换为该特定类型?

我的工作查询看起来像这样:

var allFactories = (from Node n in assets.Nodes
                    from FactoryUpgrade u in n.NodeUpgrades
                    where u.ClassID == NodeUpgradeTypes.Factory
                    select u)

当然,这不起作用。我可以指定输出的最终类型吗?

3 个答案:

答案 0 :(得分:4)

如果您确定序列中的每个类型都是给定类型,则可以使用Cast<T>()扩展方法。如果列表中可以有多种类型,并且您只需要其中一种类型,则可以使用OfType<T>()来过滤序列。

List<Animal> animals = ...

// assumes all animals are cats 
var cats = animals.Cast<Cat>();
// var cats = (from animal in animals where ... select animal).Cast<Cat>();

// or maybe animals can contain dogs, but you don't want them
var cats = animals.OfType<Cat>();

不同之处在于,如果动物不是猫,Cast会抛出异常,而OfType会在实际尝试转换之前执行类型检查。当你对统一类型有信心时,我会赞成Cast超过OfType。 (另请注意,这些执行用户定义的转换。如果已定义隐式或显式转换,则这些方法将不支持这些转换。)

每种情况下生成的序列都是IEnumerable<Cat>,您可以对其进行进一步的查询操作(过滤器,分组,投影,ToList()等)。

答案 1 :(得分:1)

正如其他人所说,使用.OfType扩展方法来过滤类型(假设您已在数据源上设置了继承模型和适当的鉴别器)。这将在数​​据库中转换为在鉴别器(ClassID)上包含适当的Where子句。

var allFactories = from n in assets.Nodes 
                   from u in n.NodeUpgrades.OfType<FactoryUpgrade>() 
                   select u;

在这种情况下,您没有在此处指定是使用EF,LINQ to SQL还是仅使用Linq to Objects。每种方法都有不同的继承建模方式。如果您需要有关建模部分的帮助,请告诉我们您正在使用的OR / M.

答案 2 :(得分:1)

您可以使用方法OfType<>

var allFactories = (from Node n in assets.Nodes
                    from FactoryUpgrade in n.NodeUpgrades
                    where u.ClassID == NodeUpgradeTypes.Factory
                    select u).OfType<ChildType>();