Я новичок в С#, просто вопрос о том, как правильно использовать IComparable и IComparer. Допустим, у нас есть следующий класс:
public class Student
{
int score;
string name;
}
и я хочу сначала отсортировать по сокре (убыванию), а затем по имени (по возрастанию).
Теперь предположим, что я не могу получить доступ к классу Student, поэтому я могу использовать только IComparer. поэтому я должен сделать один класс помощи (скажем, он называется StudentComparer) и поместить ту же логику в
public class StudentComparer: IComparer
{
int Compare(object o1, object o2)
{
Student s1 = o1 as Student;
Student s2 = o2 as Student;
// not checking null for simplicity
if (s1.score == s2.score)
return String.Compare(s1.name, s2.name);
else if (s1.score < s2.score)
return -1
else
return 1
}
}
Вот мой вопрос, если мне просто нужно использовать одно правило позже, например, иногда просто сортировать по имени, а иногда просто сортировать по счету. Поэтому мне нужно сделать еще два класса помощи (ScoreComparer и NameComparer), которые реализуют IComparer, которые дублируют код в StudentComparer как
public class ScoreComparer : IComparer
{
int Compare(object o1, object o2)
{
//half logic of StudentComparer
}
}
public class NameComparer: IComparer
{
int Compare(object o1, object o2)
{
//half logic of StudentComparer
}
}
мой случай довольно прост, представьте себе, что если есть сложный случай, каждый компаратор состоит из сотен строк кода, так как я могу избежать дублирования кода? или это способ объединить несколько компараторов A, B, C, D... в общий компаратор, чтобы он последовательно проверял A, B, C, D, как порядок по предложению в SQL
Вы можете использовать порядок по методу Linq... Чтобы отменить запись компаратора...
@HansPassant будет дублированный код
SO по-прежнему будет доступен, если вам нужно разобраться со «сложным случаем». И не думал помещать общий код в базовый класс или статические методы. Не пишите код .NET 1.0, вместо этого создайте IComparer<Student>
. Меньше ненужного кода.
Еще до появления linq я часто использовал компараторы.
Я обрабатывал различные параметры сортировки, указав эти параметры в конструкторе реализации компаратора, а затем используя эту информацию в методе Compare
.
К счастью для нас, теперь у нас есть linq, поэтому все это можно сделать с помощью одной беглой строки кода:
// sortedStudents is an IEnumerable<Student> sorted by score and name.
var sortedStudents = students.OrderBy(s => s.Score).ThenBy(s => s.Name);
Однако, если по какой-то причине вам нужно работать по старинке, используя компараторы и тому подобное, вот как я поступил бы тогда:
internal enum CompareBy
{
NameOnly,
ScoreAndName
}
public class StudentComparer: IComparer<Student>
{
private CompareBy _compareBy
public StudentComparer(CompareBy compareBy)
{
_compareBy = compareBy;
}
public int Compare(Student s1, Student s2)
{
// not checking null for simplicity
var nameCompare = string.Compare(s1.name, s2.name);
if (_compareBy == NameOnly)
{
return nameCompare;
}
// since there are only two members in the enum it's safe to write it like this.
// if the enum grows, you must change the code.
if (s1.score == s2.score)
{
return nameCompare;
}
else if (s1.score < s2.score)
{
return -1
}
return 1
}
}
У них не будет «дублированного кода», очевидно, что метод Compare() будет другим.