首先:Type.GetProperties 没有明确的顺序。
var props = typeof(T).GetProperties();
props[0] 中的属性是什么?所有属性都可读吗?
因此,如果您想获得明确的订单,我的建议是进行一些排序。例如获取按名称排序的公共可读属性。
此外,如果您的代码的用户(= 软件,而不是操作员)想要使用基于索引的通用代码,这不是有点奇怪吗?
- 他们有一个类
MyClass 和一个属性Date
- 它们有一系列此类对象。
- 他们想按属性订购
Date
- 他们必须确定属性
Date 的索引,而不是按属性Date 或名为“日期”的属性排序:日期似乎是第四个属性
- 然后他们必须使用以下索引调用您的方法:“OrderBy index 4”
如果他们只说:“按属性排序Date”或“按名为“日期”的属性排序不是更容易吗?
IEnumerable<MyClass> source = ...
var orderedSource = source.OrderBy(t => t.Date);
有时您的用户无权访问该属性,他们只知道该属性的名称。在这种情况下,您可以创建一个扩展方法,在其中提供属性的名称,并返回有序的源代码。
如果您不熟悉扩展方法。见extension methods demystified
用法类似于:
var orderedSource = source.OrderBy(nameof(MyClass.Date));
或者例如:“按我的 DataGridView 中的选定列排序”。
string propertyName = this.DataGridView.Columns.Cast<DataGridViewColumn>()
.Where(column => column.IsSelected)
.Select(column => column.DataPropertyName)
.FirstOrDefault();
var orderedSource = source.OrderBy(propertyName);
这样的程序易于制作、易于使用和重用、易于测试、易于维护。最重要的是:它们是单线:
public static IOrderedEnumerable<T> OrderBy<T>(
this IEnumerable<T> source,
string propertyName)
{
// TODO: handle invalid input
PropertyInfo propertyInfo = typeof(T).GetProperty(propertyName);
// TODO: handle invalid propertyname
return source.OrderBy(propertyInfo);
}
public static IOrderedEnumerable<T> OrderBy<T>(
this IEnumerable<T> source,
PropertyInfo propertyInfo)
{
// TODO: handle invalid parameters
return source.OrderBy(t => propertyInfo.GetValue(t) as propertyInfo.PropertyType);
}
如果需要,您可以为 ThenBy(this IEnumerable<T>, ...) 创建重载。
但我想按索引而不是按名称排序!
如果你真的想按索引排序,用 Lambda 表达式创建扩展方法会更容易,然后用表达式来摆弄。
考虑以下扩展方法:
public static IOrderedEnumerable<T> OrderBy<T>(
IEnumerable<T> source,
int propertyIndex)
{
return source.OrderBy(propertyIndex, GetDefaultPropertyOrder(typeof(T));
}
public static IOrderedEnumerable<T> OrderBy<T>(
IEnumerable<T> source,
int propertyIndex,
IReadOnlyList<PropertyInfo> properties)
{
// TODO: handle null and out-of-range parameters
PropertyInfo sortProperty = properties[propertyIndex];
return source.OrderBy(sortProperty);
}
public static IList<PropertyInfo> GetDefaultPropertyOrder(Type t)
{
return t.GetProperties()
.Where(property => property.CanRead)
.OrderBy(property => property.Name)
.ToList();
}
用法:
BindingList<MyClass> myObjects = ...
// display myObjects in a dataGridView
this.DataGridView.DataSource = myObjects;
// event if operator clicks on column header:
public void OnColumnHeaderClicked(object sender, ...)
{
DataGridViewColumn clickedColumn = GetClickedColumn();
// sort by column index, as you prefer:
var sortedObjects = myObjects.SortBy(clickedColumn.DisplayIndex);
ProcessSortedObjects(sortedObjects);
// but of course, you skip some intermediate methods if you sort by property name
var sortedObject = myObject.SortBy(clickedColumn.DataPropertyName);
ProcessSortedObjects(sortedObjects);
}