什么是实现通用比较器的最佳方式?

7

我有很多比较器类,其中被比较的类只是检查对象的名称属性并进行字符串比较。例如:

public class ExerciseSorter : IComparer<Exercise>
{
    public int Compare(Exercise x, Exercise y)
    {
        return String.Compare(x.Name, y.Name);
    }
}

public class CarSorter : IComparer<Car>
{
    public int Compare(Car x, Car y)
    {
        return String.Compare(x.Name, y.Name);
    }
}

如何使这段代码通用化,以便不需要一遍又一遍地编写冗余的代码。

3个回答

16
我使用的类似这样:

public class AnonymousComparer<T> : IComparer<T>
{
    private Comparison<T> comparison;

    public AnonymousComparer(Comparison<T> comparison)
    {
        if (comparison == null)
            throw new ArgumentNullException("comparison");
        this.comparison = comparison;
    }

    public int Compare(T x, T y)
    {
        return comparison(x, y);
    }
}

使用方法:

var carComparer = new AnonymousComparer<Car>((x, y) => x.Name.CompareTo(y.Name));

如果你正在进行属性比较,且该属性类型实现了IComparable接口(例如intstring),那么我还有这个类,它使用起来更加简洁:

public class PropertyComparer<T, TProp> : IComparer<T>
    where TProp : IComparable
{
    private Func<T, TProp> func;

    public PropertyComparer(Func<T, TProp> func)
    {
        if (func == null)
            throw new ArgumentNullException("func");
        this.func = func;
    }

    public int Compare(T x, T y)
    {
        TProp px = func(x);
        TProp py = func(y);
        return px.CompareTo(py);
    }
}

这个的用法是:

var carComparer = new PropertyComparer<Car, string>(c => c.Name);

var carComparer = new AnonymousComparer<Car>((x,y)=>x.Name.CompareTo(y.Name)) ? - spender
@spender:是的,那就是用法...我犯了错误吗?看起来和我写的一样。 - Aaronaught
第一版是 var carComparer = new AnonymousComparer<Car>(x.Name.CompareTo(y.Name))。现在已经正确了。 - spender
我在这里想念空值检查 x.Name.CompareTo()return px.CompareTo(py); - FrankM
System.Collections.Generic.ComparisonComparer 正是做这件事的。我想知道为什么这个类是 internal - bytecode77

8

从.NET 4.5开始,不需要创建一个通用类来包装Comparison<T>委托以实现IComparer<T>接口。

框架提供了Create方法,它在Comparer<T>上是静态的,接受一个Comparison<T>委托并返回一个实现了IComparer<T>Comparer<T>

以下是使用它的示例:

// Sample comparison, any T will do.
Comparison<int> comparison = (x, y) => x.CompareTo(y)

// Get the IComparer.
IComparer<T> comparer = Comparer.Create(comparison);

现在,您可以编写 lambda 表达式来执行比较,并快速将其包装在 IComparer<T> 实现中,在其中未提供使用 Comparison<T> 委托的选项(例如 List<T> 上的 Sort 方法)。

0
如果您的所有类都有Name属性,您可以引入IHaveName接口并创建以下比较器:
public class NameComparer : IComparer<IHaveName>
{
    public int Compare(IHaveName x, IHaveName y)
    {
        return String.Compare(x.Name, y.Name);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接