通过反射按自定义属性对实体进行Linq排序
本文关键字:Linq 排序 实体 反射 自定义属性 | 更新日期: 2023-09-27 18:20:57
得到具有Country
属性的Customer
类,该类具有字符串属性Name
。同样,Customer
实现IComparable<Country>
类似于
public int CompareTo(Country other)
{
return string.Compare(this.Name, other.Name);
}
现在:
var custList = new List<Customer>{...};
custList.OrderBy(cust => cust.Country).ToList(); //Sorts as charm.
如果尝试通过反射进行排序:
var itemProp = typeof(Customer).GetProperty("Country");
custList = c.Customers.ToList()
.OrderBy(cust => itemProp.GetValue(cust, null)).ToList(); // Fails
抛出异常"至少有一个对象必须实现IComparable"
请解释为什么失败,以及如何通过反射正确实现按自定义属性对Customer的排序。谢谢
由于GetValue
返回Object
,因此需要实现IComparable
的非通用版本。
void Main()
{
var custList = new List<Customer>()
{
new Customer(){ Country = new Country(){ Name = "Sweden" } },
new Customer(){ Country = new Country(){ Name = "Denmark" } },
};
var itemProp = typeof(Customer).GetProperty("Country");
custList = custList.OrderBy(cust => itemProp.GetValue(cust, null)).ToList();
custList.Dump();
}
public class Country : IComparable<Country>, IComparable
{
public string Name {get;set;}
public int CompareTo(Country other)
{
return string.Compare(this.Name, other.Name);
}
public int CompareTo(object other)
{
var o = other as Country;
if(o == null)
return 0; //Or how you want to handle it
return CompareTo(o);
}
}
public class Customer
{
public Country Country{get;set;}
}
假设底层类型是正确的(即Country
),只要Country
实现IComparable
:,您就应该能够做到这一点
以下是一个正常工作的示例控制台应用程序(请注意,没有错误处理):
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
class Number: IComparable<Number>, IComparable
{
public Number(int value)
{
Value = value;
}
public readonly int Value;
public int CompareTo(Number other)
{
return Value.CompareTo(other.Value);
}
public int CompareTo(object obj)
{
return CompareTo((Number) obj);
}
}
class Test
{
public Number Number;
public object Obj
{
get { return Number; }
}
public override string ToString()
{
return Number.Value.ToString();
}
}
internal static class Program
{
static void Main()
{
var itemProp = typeof(Test).GetProperty("Obj");
Console.WriteLine(string.Join("'n",
data().OrderBy(x => itemProp.GetValue(x, null))));
}
static IEnumerable<Test> data()
{
for (int i = 0; i < 10; ++i)
yield return new Test {Number = new Number(10-i)};
}
}
}