【问题标题】:Implementing Enumerable.OfType<T> with Type instance argument [duplicate]使用 Type 实例参数实现 Enumerable.OfType<T> [重复]
【发布时间】:2016-10-06 14:39:02
【问题描述】:

我正在尝试实现 OfType 的替代方案,您将所需的类型指定为 Type 实例参数,而不是使用类型参数化,但我不确定实现它的“正确方法”是什么。这是我目前所拥有的:

public static IEnumerable<T> OfType<T>(this IEnumerable<T> enumerable, Type type)
{
    return enumerable.Where(element => type.IsInstanceOfType(element));
}

我最初是从下面的代码开始的,但意识到它不支持继承......

public static IEnumerable<T> OfType<T>(this IEnumerable<T> enumerable, Type type)
{
    return enumerable.Where(element => element.GetType() == type);
}

然后我考虑了几秒钟比较基本类型,然后才想到这可能是个坏主意。

所以我的问题是,在提供的类型相同的情况下,顶部的代码是否总是返回与 OfType 相同的结果?换句话说,下面代码示例中的集合parametrizedFilteredtypeInstanceFiltered 是否会包含相同的元素,或者我会走多远?

IEnumerable<InterfaceType> someCollection = BlackBox.GetCollection();
IEnumerable<DerivedType> parametrizedFiltered = someCollection.OfType<DerivedType>();
IEnumerable<InterfaceType> typeInstanceFiltered = someCollection.OfType(typeof(DerivedType));

【问题讨论】:

  • 您可以查看IsAssignableFrom 进行“深度”继承检查。
  • @JeroenvanLangen 我认为IsAssignableFrom(x.GetType()) 等效于IsInstanceOfType(x),当您忽略null 情况时。不过,缓存 IsAssignableFrom 的结果可能会提高性能。
  • 数组协方差和可空值类型的行为相同。接口协方差也应该起作用。
  • 所以你基本上是在问obj is TResult是否与typeof(TResult).IsInstanceOfType(obj)相同
  • 主要区别在于OfType 返回您指定的类型的IEnumerable,因为您正在执行的操作将返回原始类型的IEnumerable “匹配”已过滤。

标签: c# linq generics reflection types


【解决方案1】:

如果您想知道您的实现是否会给出与Enumerable.OfType&lt;&gt; 相同的结果,那么它会。

Enumerable.OfType&lt;&gt; 使用is 作为其实现,正如this answer 所示,is 关键字将给出与Type.IsAssignableFrom() 相同的结果。

您需要的另一条信息是IsInstanceOfType() 是使用IsAssignableFrom 实现的:

public virtual bool IsInstanceOfType(Object o)
{
    if (o == null)
        return false;

    // No need for transparent proxy casting check here
    // because it never returns true for a non-rutnime type.

    return IsAssignableFrom(o.GetType());
}

下面的测试代码会打印出来

Demo.Base
Demo.Derived

这表明您的原始代码确实适用于继承:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Demo
{
    public class Base {}
    public class Derived : Base {}

    class Program
    {
        static void Main()
        {
            object[] array = {"String", new Base(), new Derived(), 12345};

            foreach (var item in OfType(array, typeof(Base)))
                Console.WriteLine(item);
        }

        public static IEnumerable<T> OfType<T>(IEnumerable<T> enumerable, Type type)
        {
            return enumerable.Where(element => type.IsInstanceOfType(element));
        }
    }
}

请注意,因为 IsInstanceOfType() 是使用 IsAssignableFrom 实现的,所以您可以这样编写方法:

public static IEnumerable<T> OfType<T>(this IEnumerable<T> enumerable, Type type)
{
    return enumerable.Where(element => type.IsAssignableFrom(element.GetType()));
}

【讨论】:

  • close 你的意思是 identical?
  • @CodesInChaos 糟糕,我正在查看他的第二个代码示例。是的,我想这个答案是多余的。 :) 将编辑。
  • @SindriJóelsson 由于Type.IsInstanceOfType() 将给出与is 运算符相同的结果,并且由于Enumerable.OfType&lt;&gt; 使用is 进行实现,因此这两种方法将给出相同的结果。这不是你想要的吗?
  • 您的问题是So my question is will the code at the top always return the same result as OfType given the types provided are the same?,因此答案是Yes, it will,因为isType.IsInstanceOfType() 的工作方式相同。
  • 届时我会将您的答案标记为已接受。
猜你喜欢
  • 2015-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-05
相关资源
最近更新 更多