【问题标题】:What is the difference between ((IEnumerable)source).OfType<T>() and source as IEnumerable<T>((IEnumerable)source).OfType<T>() 和 source as IEnumerable<T> 有什么区别
【发布时间】:2010-09-17 21:51:15
【问题描述】:

((IEnumerable)source).OfType&lt;T&gt;()source as IEnumerable&lt;T&gt;有什么区别

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

source 的类型为 IEnumerable&lt;T&gt;,但它被装箱为 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");
};

【问题讨论】:

  • 这是一个测验问题吗?你似乎遗漏了一些信息。无论如何,OfType 只过滤掉该类型的可枚举元素,所以这是最大的区别。
  • 我在我的代码源中使用了 IEnumerable 并证明它不为空,但它为空。我查看了调试器,发现 T 是正确的。然后我使用 ((IEnumerable)source).OfType() 并且转换是正确的,没有空结果。如果你愿意,我可以发布更多代码。

标签: c# linq casting ienumerable boxing


【解决方案1】:

((IEnumerable)source).OfType&lt;T&gt;()source as IEnumerable&lt;T&gt; 之间有什么区别?对我来说,它们看起来很相似,但实际上并不相似!

你是对的。它们非常不同。

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

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

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

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

这会给你一个新的、不同的序列,其中包含一只老虎。

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

这会给你null。动物不是哺乳动物的序列,即使它是恰好是哺乳动物的动物序列。动物的实际运行时类型是“动物数组”,并且动物数组与哺乳动物序列的类型不兼容。为什么不?好吧,假设转换成功,然后你说:

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

嘿,你只是把一条蛇放到一个只能包含哺乳动物的变量中!我们不能允许这样,所以转换不起作用。

在 C# 4 中,您可以走另一条路。你可以这样做:

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

因为一组动物可以被视为一系列对象。你把一条蛇放在那里,一条蛇仍然是一个物体。不过,这只适用于 C# 4。 (并且只有当这两种类型都是 reference 类型时才有效。你不能将 int 数组转换为对象序列。)

但要理解的关键是OfType&lt;T&gt; 方法返回一个全新的序列,而“as”运算符进行运行时类型测试。这些是完全不同的东西。

这是另一种看待它的方式。

tigers = animals.OfType&lt;Tiger&gt;()

基本相同
tigers = animals.Where(x=>x is Tiger).Select(x=>(Tiger)x);

也就是说,通过对动物的每个成员进行测试来查看它是否是老虎,从而产生一个新序列。如果是,请投射它。如果不是,则丢弃它。

mammals = animals as IEnumerable&lt;Mammal&gt;另一方面,和

基本一样
if (animals is IEnumerable<Mammal>)
    mammals = (IEnumerable<Mammal>) animals;
else
    mammals = null;

有意义吗?

【讨论】:

    【解决方案2】:

    OfType&lt;T&gt;() 只会返回枚举中类型为 T 的类型。所以如果你有这个

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

    然后调用

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

    那么 myStrings 将是一个可枚举的对象,它会跳过 1 和 2,只返回“hi”和“there”。您不能将 myObjects 转换为 IEnumerable&lt;string&gt;,因为它不是这样的。

    与此类似的另一个运算符是Cast&lt;T&gt;(),它将尝试将所有项目转换为类型 T。

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

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

    【讨论】:

    • 是的,但我的类型都是一样的。 Cast 是否类似于 IEnumerable
    猜你喜欢
    • 2020-01-15
    • 1970-01-01
    • 1970-01-01
    • 2011-06-25
    • 2011-05-31
    • 2021-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多