复杂对象的自然排序抽象类
本文关键字:排序 抽象类 自然 对象 复杂 | 更新日期: 2023-09-27 18:32:03
All,
我正在创建一个类,以按类中的指定字符串属性对对象列表进行排序。我是通过继承 IComparer 和 List 提供的 Sort() 方法来做到这一点的。
我的比较器类是抽象的,因此可以在任何对象类型上调用它,当然,前提是有一个字符串属性可以进行比较。
我遇到的问题是如何指定该类正在处理的泛型类的字符串属性类型。在下面的代码中,我有一个名为"MyObjectsStringProperty"的占位符,这就是我正在努力解决的问题。如何在这些位置提供有效的语法。
谢谢
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace NaturalSorterDemo
{
public abstract class NaturalComparerObject<T> : Comparer<T>, IDisposable
{
private Dictionary<string, string[]> _table;
protected NaturalComparerObject()
{
_table = new Dictionary<string, string[]>();
}
public void Dispose()
{
_table.Clear();
_table = null;
}
public override int Compare(T x, T y)
{
if (x.MyObjectsStringProperty.ToLower() == y.MyObjectsStringProperty.ToLower())
{
return 0;
}
string[] x1, y1;
if (!_table.TryGetValue(x.MyObjectsStringProperty.ToLower(), out x1))
{
x1 = Regex.Split(x.MyObjectsStringProperty.Replace(" ", ""), "([0-9]+)");
_table.Add(x.MyObjectsStringProperty.ToLower(), x1);
}
if (!_table.TryGetValue(y.MyObjectsStringProperty.ToLower(), out y1))
{
y1 = Regex.Split(y.MyObjectsStringProperty.Replace(" ", ""), "([0-9]+)");
_table.Add(y.MyObjectsStringProperty.ToLower()
, y1);
}
for (int i = 0; i < x1.Length && i < y1.Length; i++)
{
if (x1[i].ToLower() != y1[i].ToLower())
{
return PartCompare(x1[i], y1[i]);
}
}
if (y1.Length > x1.Length)
{
return 1;
}
else if (x1.Length > y1.Length)
{
return -1;
}
else
{
return 0;
}
}
private static int PartCompare(string left, string right)
{
int x, y;
left = left.ToLower();
right = right.ToLower();
if (!int.TryParse(left, out x))
{
return left.CompareTo(right);
}
if (!int.TryParse(right, out y))
{
return left.CompareTo(right);
}
return x.CompareTo(y);
}
}
}
首先,代码示例存在一些根本性错误:
- 该类无缘无故地
abstract
。如果类中没有abstract
成员,则不要使类本身abstract
。 - 该类无缘无故地实现
IDisposable
。该接口主要用于处理非托管资源。这里不需要它,您甚至也不太可能公开任何机制来清除私有词典。字典将在类本身时被收集,并且大概在发生这种情况之前,字典仍然有用。 - 使用
ToLower()
作为实现不区分大小写的比较的一种方式并不完全安全;它依赖于区域性,但不适用于字符串比较。至少,您应该使用ToLowerInvariant()
.但是,即使这对您来说很可靠,它仍然会导致无缘无故地创建大量新的字符串实例。正确的方法是使用指定不区分大小写的比较的StringComparison
值之一或适当的StringComparer
实例(适用于字典使用)执行所有字符串比较。在 .NET Framework 中使用字符串的最佳实践以及您的代码是否通过了土耳其测试?是一些相关资源供您查看。
其次,在我看来,这里实际上并不需要泛型类型。正如 Servy 在评论中提到的,最好限制此处的功能并根据需要进行组合。你可以为调用方提供一种指定选择器的方法,但鉴于 .NET 已经提供了易于组合的IComparer<T>
功能,这在这里似乎是多余的。
因此,如果您使类型看起来像这样:
public abstract class NaturalComparerObject : Comparer<string>
{
private Dictionary<string, string[]> _table;
protected NaturalComparerObject()
{
_table = new Dictionary<string, string[]>();
}
public override int Compare(string x, string y)
{
// implementation omitted for brevity
}
}
然后你可以像这样使用它:
NaturalComparerObject stringComparer = new NaturalComparerObject();
myList.Sort((x, y) =>
stringComparer.Compare(x.MyObjectsStringProperty, y.MyObjectsStringProperty));
最后,我建议你可能真的不需要字典,这意味着你的比较实现可能只是一个静态方法。字典似乎在那里缓存删除空格和拆分数字的结果,这些操作当然是昂贵的,尤其是在对象创建方面。但是,只需稍加努力,您就可以编写一个比较,该比较只是遍历字符串的字符,而不必首先创建促使使用字典的中间对象。
由于您没有缓存比较结果,因此字典唯一可以帮助您避免的是对象创建的开销。您仍然需要比较原始字符串的各个部分的成本,因此执行相同操作但不创建中间对象的实现将执行大致相同的操作,但没有所有额外的内存开销(即使使用缓存,该字典和其中包含的对象对于具有大量字符串的任何方案来说都是昂贵的)。