You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

泛型Table类中基于未知类型属性的LINQ排序问题

解决泛型Table的动态属性排序问题

你当前代码排序无效的核心原因是:e.GetType().GetProperty("Surname")返回的是属性的元数据对象(PropertyInfo),而非该属性在实例e上的实际值。OrderBy会基于这些PropertyInfo对象排序(而它们本身都是同一个实例),自然不会改变数据的顺序。

下面是三种可行的解决方式,按性能从低到高排序:

1. 直接通过反射获取属性值排序

修改排序代码,调用PropertyInfo.GetValue()拿到实例的属性值作为排序依据:

// 注意处理属性不存在的情况,避免NullReferenceException
var prop = _data[0].GetType().GetProperty("Surname");
if (prop != null)
{
    _data = _data.OrderBy(e => prop.GetValue(e)).ToList<T>();
}

这种方式简单直接,但反射调用GetValue性能较低,频繁排序时会有明显开销。

2. 缓存PropertyInfo提升性能

既然表头是提前生成的,可以在生成表头时缓存每个列对应的PropertyInfo,避免每次排序重复反射:

// 在类中定义缓存字典
private Dictionary<string, PropertyInfo> _propertyCache = new Dictionary<string, PropertyInfo>();

// 生成表头时填充缓存
public void InitializeColumns(List<T> data)
{
    if (data == null || data.Count == 0) return;
    var properties = data[0].GetType().GetProperties();
    foreach (var prop in properties)
    {
        _propertyCache[prop.Name] = prop;
        // 此处添加表头元素及点击事件绑定
    }
}

// 表头点击时的排序逻辑
private void OnHeaderClick(string propertyName)
{
    if (_propertyCache.TryGetValue(propertyName, out var prop))
    {
        _data = _data.OrderBy(e => prop.GetValue(e)).ToList<T>();
        // 更新表格显示
    }
}

这种方式减少了重复反射的开销,比第一种更高效。

3. 用表达式树构建强类型委托(最优性能)

反射的性能始终不如强类型调用,我们可以用表达式树将PropertyInfo编译为Func<T, object>委托,让排序时直接调用强类型方法,性能接近原生代码:

// 缓存编译后的委托
private Dictionary<string, Func<T, object>> _accessorCache = new Dictionary<string, Func<T, object>>();

// 生成表头时编译委托并缓存
public void InitializeColumns(List<T> data)
{
    if (data == null || data.Count == 0) return;
    var properties = data[0].GetType().GetProperties();
    foreach (var prop in properties)
    {
        // 构建表达式树并编译为委托
        var param = Expression.Parameter(typeof(T));
        var propertyAccess = Expression.Property(param, prop);
        // 装箱为object(适配Func<T, object>)
        var convert = Expression.Convert(propertyAccess, typeof(object));
        var accessor = Expression.Lambda<Func<T, object>>(convert, param).Compile();
        
        _accessorCache[prop.Name] = accessor;
        // 添加表头及点击事件
    }
}

// 排序逻辑
private void OnHeaderClick(string propertyName)
{
    if (_accessorCache.TryGetValue(propertyName, out var accessor))
    {
        _data = _data.OrderBy(accessor).ToList<T>();
        // 更新表格显示
    }
}

这种方式在首次编译委托时有一点开销,但后续排序的性能和直接写e => e.Surname几乎一致,适合频繁排序的场景。

另外,你还可以扩展逻辑,添加升降序切换:比如记录当前排序的属性名和排序方向,点击时切换OrderBy为OrderByDescending,或者反转已排序的列表。

内容的提问来源于stack exchange,提问作者Peter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 22:02:22