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

反转比较器装饰器:如何避免名称比较被二次反转

解决方案

要实现主排序(类型)反转、次排序(名称)保持原方向的需求,核心是避免将整个组合比较逻辑一次性反转,而是拆分主/次比较器,仅反转主比较逻辑后再与原次比较器重新组合。

1. 重构比较器结构(推荐,提升复用性)

首先添加ThenBy扩展方法,用于组合主、次比较器,让排序逻辑更模块化:

public static class ComparerExtensions
{
    // 组合主、次比较器:主比较结果不为0时用主结果,否则用次比较结果
    public static IComparer<T> ThenBy<T>(this IComparer<T> primary, IComparer<T> secondary)
    {
        if (primary == null) throw new ArgumentNullException(nameof(primary));
        if (secondary == null) throw new ArgumentNullException(nameof(secondary));
        
        return Comparer<T>.Create((x, y) =>
        {
            int primaryResult = primary.Compare(x, y);
            return primaryResult != 0 ? primaryResult : secondary.Compare(x, y);
        });
    }

    // 仅反转当前比较器的逻辑(不影响后续组合的比较器)
    public static IComparer<T> Reverse<T>(this IComparer<T> other)
    {
        if (other == null) throw new ArgumentNullException(nameof(other));
        
        return other is ReverseComparer<T> reverse ? reverse.Other : new ReverseComparer<T>(other);
    }

    public class ReverseComparer<T> : IComparer<T>
    {
        public ReverseComparer(IComparer<T> other)
        {
            Other = other ?? throw new ArgumentNullException(nameof(other));
        }
        
        public IComparer<T> Other { get; }

        public int Compare(T? x, T? y)
        {
            return Other.Compare(y, x);
        }
    }
}

然后拆分原有的MyComparison,将类型、名称比较逻辑分离:

public static class MyComparison
{
    // 仅比较类型的基础比较器(升序)
    public static readonly IComparer<MyModel> TypeOnly =
        Comparer<MyModel>.Create((l, r) => l.Type.CompareTo(r.Type));

    // 仅比较名称的基础比较器(升序)
    public static readonly IComparer<MyModel> Name =
        Comparer<MyModel>.Create((l, r) => l.Name.CompareTo(r.Name));

    // 组合逻辑:先类型升序,再名称升序(与原逻辑一致)
    public static readonly IComparer<MyModel> TypeThenName = TypeOnly.ThenBy(Name);
}

现在只需一行代码就能实现类型降序、名称升序的需求:

// 反转类型比较器,再与原名称比较器组合
var typeDescNameAsc = MyComparison.TypeOnly.Reverse().ThenBy(MyComparison.Name);

2. 直接创建目标比较器(快速实现)

如果不想重构现有代码,也可以直接编写目标逻辑,跳过扩展方法:

var typeDescNameAsc = Comparer<MyModel>.Create((l, r) =>
{
    // 类型降序:用r.Type和l.Type比较
    int typeResult = r.Type.CompareTo(l.Type);
    if (typeResult != 0) return typeResult;
    // 名称保持升序:用原逻辑比较
    return l.Name.CompareTo(r.Name);
});

问题根源说明

原反转逻辑会同时反转名称排序,是因为MyComparison.Type是一个包含了类型+名称的整体比较器,调用Reverse时会将整个比较逻辑反转(包括类型和名称的比较顺序)。通过拆分主/次比较器,我们仅反转主排序逻辑,再与原次排序逻辑组合,就完美规避了这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:46:17