((IEnumerable)source).OfType<T>() 和 source as IEnumerable<T> 有什么区别?

4

((IEnumerable)source).OfType<T>()source as IEnumerable<T>有什么区别?

对我来说它们看起来很相似,但实际上并不是这样!

source的类型是IEnumerable<T>,但它被装箱成了一个object

编辑

以下是一些代码:

public class PagedList<T> : List<T>, IPagedList
{
    public PagedList(object source, int index, int pageSize, int totalCount)
    {
        if (source == null)
            throw new ArgumentNullException("The source is null!");


        // as IEnumerable<T> gives me only null

        IEnumerable<T> list = ((IEnumerable)source).OfType<T>();

        if (list == null)
            throw new ArgumentException(String.Format("The source is not of type {0}, the type is {1}", typeof(T).Name, source.GetType().Name));

        PagerInfo = new PagerInfo
                        {
                            TotalCount = totalCount,
                            PageSize = pageSize,
                            PageIndex = index,
                            TotalPages = totalCount / pageSize
                        };

        if (PagerInfo.TotalCount % pageSize > 0)
            PagerInfo.TotalPages++;

        AddRange(list);
    }

    public PagerInfo PagerInfo { get; set; }
}

在另一个地方,我创建了一个PagedList的实例。
public static object MapToPagedList<TSource, TDestination>(TSource model, int page, int pageSize, int totalCount) where TSource : IEnumerable
{
    var viewModelDestinationType = typeof(TDestination);
    var viewModelDestinationGenericType = viewModelDestinationType.GetGenericArguments().FirstOrDefault();

    var mappedList = MapAndCreateSubList(model, viewModelDestinationGenericType);

    Type listT = typeof(PagedList<>).MakeGenericType(new[] { viewModelDestinationGenericType });
    object list = Activator.CreateInstance(listT, new[] { (object) mappedList,  page, pageSize, totalCount });

    return list;
}

如果有人能告诉我为什么我需要将mappedList转换为对象,我将不胜感激 :)

下面是MapAndCreateSubList方法和Map委托:

private static List<object> MapAndCreateSubList(IEnumerable model, Type destinationType)
{
    return (from object obj in model select Map(obj, obj.GetType(), destinationType)).ToList();
}

 public static Func<object, Type, Type, object> Map = (a, b, c) =>
{
    throw new InvalidOperationException(
        "The Mapping function must be set on the AutoMapperResult class");
};

1
这是一道测验题吗?你似乎省略了一些信息。无论如何,OfType<T>会过滤掉枚举中不属于该类型的元素,这就是最大的区别。 - Kirk Woll
我在我的代码中使用了IEnumerable<T>,并验证它不为空,但实际上它是空的。我在调试器中查看后发现T是正确的。然后我使用了((IEnumerable)source).OfType<T>(),强制转换是正确的,没有出现空结果。如果您需要,我可以发布更多代码。 - Rookian
2个回答

12

((IEnumerable)source).OfType<T>()

source as IEnumerable<T>

你说得对,它们非常不同。

前者的意思是:“获取源序列并生成一个全新的、不同的序列,由前一个序列中给定类型的所有元素组成。”

后者的意思是:“如果源序列的运行时类型是给定类型,则给我一个对该序列的引用,否则返回 null。”

让我举个例子来说明。假设你有:

IEnumerable<Animal> animals = new Animal[] { giraffe, tiger };
IEnumerable<Tiger> tigers = animals.OfType<Tiger>();

这将返回一个新的、不同的序列,其中包含单个老虎。

IEnumerable<Mammal> mammals = animals as IEnumerable<Mammal>;

这将给你一个空值。Animals不是哺乳动物的序列,即使它是一些仅包括哺乳动物的动物序列。实际的运行时类型是"动物数组",而动物数组与哺乳动物序列不兼容。为什么?因为假设转换成功了,然后你说:

animals[0] = snake;
Mammal mammal = mammals.First();

嘿,你刚刚将一条蛇放入了一个只能容纳哺乳动物的变量中!我们不能允许这种情况发生,因此转换不起作用。

在 C# 4 中,你可以反向操作。你可以这样做:

IEnumerable<Object> objects = animals as IEnumerable<Object>;

因为动物的数组 可以 被视为对象的序列。你在其中放入一条蛇,蛇仍然是一个对象。但这只适用于C# 4。 (并且它仅适用于两种类型都是引用类型的情况。您无法将整数数组转换为对象序列。)

但关键要理解的是,OfType<T> 方法 返回全新的序列,“as”运算符进行运行时类型检测。这些完全不同。

以下是另一种看待它的方式。

tigers = animals.OfType<Tiger>() 基本上就像

tigers = animals.Where(x=>x is Tiger).Select(x=>(Tiger)x);

即,通过对动物序列中的每个成员进行测试,以查看它是否是老虎来生成新序列。如果是,则进行类型转换。如果不是,则丢弃它。

另一方面,mammals = animals as IEnumerable<Mammal>基本上与

if (animals is IEnumerable<Mammal>)
    mammals = (IEnumerable<Mammal>) animals;
else
    mammals = null;

听懂了吗?


3

OfType<T>() 只会返回枚举中类型为 T 的类型。因此,如果您有以下内容:

object[] myObjects = new object[] { 1, 2, "hi", "there" };

那么就请您调用。
var myStrings = myObjects.OfType<string>();

那么,myStrings将是一个可枚举对象,它将跳过1和2,只返回"hi"和"there"。你不能将myObjects强制转换为 IEnumerable<string>,因为它不是这样的。

在这里类似的另一个运算符是Cast<T>(),它将尝试将所有项目转换为类型T。

   var myStrings = myObjects.Cast<string>();

一旦你开始在这种情况下迭代myStrings,你将会收到一个InvalidCastException,因为它会尝试将1转换为字符串并失败。

是的,但我的类型都是相同的。Cast<T>和as IEnumerable<T>类似吗? - Rookian

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