我们使用实体框架和“POCO”生成器来创建我们的类型,这些类型可以传递到各个层,它们属于(为了保护无辜的)命名空间 Company.Application.Project.Module。这些 POCO 对象都继承自一个为我们处理一些基本内容的基类。
我想编写一个函数,可以获取这些对象的集合并按属性名称对它们进行排序。
我编写了以下函数——它完成了我想做的事情,但我不喜欢它有几个原因:
1)这不适用于任何对象类型,它必须是 SortHelper 类知道的对象类型(因此最后一个 using 语句)。
2)“POCO”对象的 Type 和 BaseType 似乎不一致 - 取决于您在应用程序中调用此函数的位置(单元测试项目与从我们的 MVP 应用程序的演示者对象调用),这会导致线路出现问题我加粗了,因为如果它抓取了错误的类型,属性就不会出现在下面的行中。
从演示者对象中,.GetType 显示为:ClassName_96D74E07A154AE7BDD32624F3B5D38E7F50333608A89B561218F854513E3B746 ...在 System.Data.Entity.DynamicProxies 命名空间内。
这就是为什么代码在该行上显示 .GetType().BaseType 的原因,这给了我: ClassName ...within Company.Application.Project.Module
但在单元测试中, .GetType() 在 Company.Application.Project.Module 中显示为 ClassName
BaseType 在 Company.Application.Project.Module 中显示为 BaseClass
...这更有意义,但我不理解不一致 - 而且不一致让我害怕。
3)一般讨厌使用反射来做到这一点。
如果有人有更好的方法来做到这一点,或者甚至是使反射与命名空间/类型一起运行的修复程序——我当然会很感激!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Company.Application.Project.Module;
namespace Company.Application.Project
{
public static class SortHelper
{
public static IOrderedQueryable<T> Sort<T>(this IQueryable<T> source, string propertyName, bool descending)
{
// bail out if there's nothing in the list
if (source == null)
{
return null;
}
if (source.Count() == 0)
{
return source as IOrderedQueryable<T>;
}
// get the type -- or should it be the BaseType? Nobody knows!
Type sourceType = source.First().GetType().BaseType;
// this works fine _assuming_ we got the correct type on the line above
PropertyInfo property = sourceType.GetProperty(propertyName);
if (descending)
{
return source.OrderByDescending(e => property.GetValue(e, null));
}
else
{
return source.OrderBy(e => property.GetValue(e, null));
}
}
}
}