通过反射按自定义属性对实体进行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的排序。谢谢

通过反射按自定义属性对实体进行Linq排序

由于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)};
        }
    }
}