многократное правило сортировки с IComparable и IComparer? - PullRequest
0 голосов
/ 28 мая 2019

Я новичок в C #, просто вопрос о том, как правильно использовать IComparable и IComparer. Допустим, у нас есть следующий класс:

public class Student
{
    int score;
    string name;
}

и я хочу сначала отсортировать по socre (desc), а затем отсортировать по имени (asc).

Теперь предположим, что я не могу получить доступ к классу 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
   }
}

мой случай довольно прост, представьте, что если есть сложный случай, каждый компаратор состоит из сотен строк кода, так как я могу избежать дублирования кода? или это способ объединить несколько Comparer A, B, C, D ... в общий Comparer так, чтобы он проверял A, B, C, D в последовательности, точно так же, как в выражении order by в SQL

1 Ответ

1 голос
/ 28 мая 2019

В те дни, когда еще не было 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
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...