У меня есть класс, который реализует интерфейс IList. Мне требуется «отсортированное представление» этого списка, но без его изменения (я не могу отсортировать напрямую класс IList).
Эти представления должны обновляться при изменении исходного списка, сохраняя элементы отсортированными. Итак, я ввел метод создания SortList, который создает SortList, в котором есть средство сравнения для конкретного объекта, содержащегося в исходном списке.
Вот фрагмент кода:
public class MyList<T> : ICollection, IList<T>
{
public SortedList CreateSortView(string property)
{
try
{
Lock();
SortListView sortView;
if (mSortListViews.ContainsKey(property) == false)
{
// Create sorted view
sortView = new SortListView(property, Count);
mSortListViews.Add(property, sortView);
foreach (T item in Items)
sortView.Add(item);
} else
sortView = mSortListViews[property];
sortView.ReferenceCount++;
return (sortView);
}
finally
{
Unlock();
}
}
public void DeleteSortView(string property)
{
try
{
Lock();
// Unreference sorted view
mSortListViews[property].ReferenceCount--;
// Remove sorted view
if (mSortListViews[property].ReferenceCount == 0)
mSortListViews.Remove(property);
}
finally
{
Unlock();
}
}
protected class SortListView : SortedList
{
public SortListView(string property, int capacity)
: base(new GenericPropertyComparer(typeof(T).GetProperty(property, BindingFlags.Instance | BindingFlags.Public)), capacity)
{
}
public int ReferenceCount = 0;
public void Add(T item)
{
Add(item, item);
}
public void Remove(T item)
{
base.Remove(item);
}
class GenericPropertyComparer : IComparer
{
public GenericPropertyComparer(PropertyInfo property)
{
if (property == null)
throw new ArgumentException("property doesn't specify a valid property");
if (property.CanRead == false)
throw new ArgumentException("property specify a write-only property");
if (property.PropertyType.GetInterface("IComparable") == null)
throw new ArgumentException("property type doesn't IComparable");
mSortingProperty = property;
}
public int Compare(object x, object y)
{
IComparable propX = (IComparable)mSortingProperty.GetValue(x, null);
IComparable propY = (IComparable)mSortingProperty.GetValue(y, null);
return (propX.CompareTo(propY));
}
private PropertyInfo mSortingProperty = null;
}
private Dictionary<string, SortListView> mSortListViews = new Dictionary<string, SortListView>();
}
Практически, пользователи класса запрашивают создание SortListView с указанием имени свойства, которое определяет сортировку, и с помощью отражения каждый SortListView определяет IComparer, который сохраняет отсортированные элементы.
Каждый раз, когда элемент добавляется или удаляется из исходного списка, каждый созданный SortListView будет обновляться с использованием одной и той же операции.
Кажется, это хорошо с первого взгляда, но это создает мне проблемы, поскольку дает следующее исключение при добавлении элементов в список сортировки:
System.ArgumentException: элемент уже добавлен. Введите словарь: «PowerShell_ISE [C: \ Windows \ sysWOW64 \ WindowsPowerShell \ v1.0 \ PowerShell_ISE.exe]» Добавляемый ключ: «PowerShell_ISE [C: \ Windows \ system32 \ WindowsPowerShell \ v1.0 \ PowerShell_ISE.exe]»
Как видно из сообщения об исключении, выданного SortedListView.Add(object)
, строковое представление ключа (объекта элемента списка) отличается (обратите внимание на путь исполняемого файла).
Почему SortList дает мне это исключение?
Чтобы решить эту проблему, я попытался реализовать GetHashCode()
для базового объекта, но безуспешно:
public override int GetHashCode()
{
return (
base.GetHashCode() ^
mApplicationName.GetHashCode() ^
mApplicationPath.GetHashCode() ^
mCommandLine.GetHashCode() ^
mWorkingDirectory.GetHashCode()
);
}