((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转换为object,我会非常感激:)
这里是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");
};
答案 0 :(得分: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>;
那会给你null。动物不是哺乳动物的序列,即使它是一系列恰好只是哺乳动物的动物。动物的实际运行时类型是“动物阵列”,并且一系列动物与哺乳动物序列不是类型相容的。为什么不?好吧,假设转换有效,然后你说:
animals[0] = snake;
Mammal mammal = mammals.First();
嘿,你只是把蛇放进一个只能包含哺乳动物的变量中!我们不能允许,因此转换不起作用。
在C#4中你可以走另一条路。你可以这样做:
IEnumerable<Object> objects = animals as IEnumerable<Object>;
因为动物的数组可以被视为一系列对象。你把蛇放在那里,蛇仍然是一个物体。这仅适用于C#4。 (并且只有当两种类型都是引用类型时它才有效。你不能将int数组转换为对象序列。)
但要理解的关键是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;
有意义吗?
答案 1 :(得分: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强制转换为字符串并失败。