You need to enable JavaScript to run this app. 在C#属性中执行集合排序并设置排名是否合理?有无更优实现方案?
优惠活动
大模型
产品
解决方案
定价
更多

在C#属性中执行集合排序并设置排名是否合理?有无更优实现方案?

现有实现存在的问题
  • 性能损耗严重:每次访问属性都会触发全集合排序,同时遍历中调用IndexOf查找每个元素的索引,时间复杂度达到O(n²),集合元素量大时性能问题会非常明显。
  • 存在非预期副作用:直接修改原始Score对象的排名属性,若其他代码逻辑也引用了相同的Score实例,会意外拿到被修改的排名值,多线程访问时还会出现数据竞争问题。
  • 不符合属性设计规范:属性的get访问器默认应是轻量、无副作用的操作,当前实现包含重计算逻辑且会修改原始数据,容易给调用方造成误解。
  • 同分排名逻辑不合理:默认相同分数的元素会按照在列表中的顺序分配不同排名,如果业务需要同分同排名,现有逻辑无法满足。
优化方案

方案1:最小改动修复现有问题(适合访问频率低、集合量小的场景)

首先优化排序和索引计算逻辑,去掉低效的IndexOf调用,同时将重计算逻辑改为方法,明确告知调用方该操作有计算成本:

private readonly ICollection<Score> _winningTable = new List<Score>();

public List<Score> GetWinningTable()
{
    var orderedList = _winningTable.OrderByDescending(w => w.Score).ToList();
    // 用索引循环直接获取位置,避免每次查找索引
    for (int i = 0; i < orderedList.Count; i++)
    {
        orderedList[i].EditScore((decimal)orderedList[i].Score, i + 1);
    }
    return orderedList;
}

方案2:无副作用实现(推荐,不修改原始Score对象)

如果不希望修改原始Score实例,建议返回DTO存储排名,避免影响其他引用该实例的逻辑:

// 定义带排名的DTO
public class RankedScore
{
    public Score ScoreInfo { get; set; }
    public int Rank { get; set; }
}

public List<RankedScore> GetWinningTable()
{
    return _winningTable
        .OrderByDescending(w => w.Score)
        .Select((score, index) => new RankedScore
        {
            ScoreInfo = score,
            Rank = index + 1
        })
        .ToList();
}

方案3:写入时更新缓存(适合读多写少的场景)

如果榜单更新频率低、访问频率高,建议在集合新增/删除/修改元素时统一计算排名并缓存,读取时直接返回缓存结果,避免每次访问都重复计算:

private readonly List<Score> _winningTable = new List<Score>();
private List<RankedScore> _cachedRankedTable;
private bool _isCacheDirty = true; // 标记数据是否变更,需要重算缓存

// 新增元素示例
public void AddScore(Score score)
{
    _winningTable.Add(score);
    _isCacheDirty = true;
}

// 删除元素示例
public void RemoveScore(Score score)
{
    if (_winningTable.Remove(score))
    {
        _isCacheDirty = true;
    }
}

public List<RankedScore> GetWinningTable()
{
    if (_isCacheDirty)
    {
        _cachedRankedTable = _winningTable
            .OrderByDescending(w => w.Score)
            .Select((score, index) => new RankedScore
            {
                ScoreInfo = score,
                Rank = index + 1
            })
            .ToList();
        _isCacheDirty = false;
    }
    // 返回副本避免外部修改缓存数据
    return new List<RankedScore>(_cachedRankedTable);
}

同分同排名实现扩展

如果业务需要相同分数的元素排名一致,可调整排名计算逻辑:

public List<RankedScore> GetWinningTableWithSameRank()
{
    var orderedList = _winningTable.OrderByDescending(w => w.Score).ToList();
    int rank = 1;
    var result = new List<RankedScore>();
    for (int i = 0; i < orderedList.Count; i++)
    {
        if (i > 0 && orderedList[i].Score != orderedList[i-1].Score)
        {
            rank = i + 1;
        }
        result.Add(new RankedScore
        {
            ScoreInfo = orderedList[i],
            Rank = rank
        });
    }
    return result;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 05:21:01