Использование IComparer <> с функцией делегата для поиска - PullRequest
2 голосов
/ 09 июля 2010

Это похоже на слишком простой вопрос, который можно найти в Google, я думаю / надеюсь, я застрял в деталях, пытаясь реализовать свою собственную версию. То, что я пытаюсь сделать, это отсортировать список объектов MyClass в зависимости от моего объекта Datatype. Должны использоваться разные функции поиска.

Я имел в виду нечто подобное для класса Datatype:

class Datatype {
  public delegate int CMPFN(object x, object y);
  private CMPFN compareFunction;

  (...)

  private XsdDatatype((...), CMPFN compareFunction) {
      (...)
      this.compareFunction = compareFunction;
  }

  public CMPFN GetCompareFunction() {
    return this.compareFunction;
  }

  static private int SortStrings(object a, object b) {
      return ((MyClass)a).GetValue().CompareTo(((MyClass)b).GetValue());
  }
}

А позже я пытаюсь отсортировать список MyClass примерно так:

List<MyClass> elements = GetElements();
Datatype datatype = new Datatype((...), Datatype.SortStrings);
elements.Sort(datatype.GetCompareFunction()); // <-- Compile error!

Я не слишком взволнован приведением в Datatype.SortStrings, но кажется, что это может сработать (?). Однако компилятор не соглашается и выдает мне эту ошибку в последней строке выше, и я немного не уверен, почему именно CMPFN нельзя преобразовать / привести (?) К IComparer.

Cannot convert type 'proj.Datatype.CMPFN' to 'System.Collections.Generic.IComparer<proj.MyClass>'

Ответы [ 3 ]

10 голосов
/ 09 июля 2010

Делегаты не так набираются. Вы можете создать Comparison<MyClass> из CMPFN, но вы не можете использовать простое преобразование ссылок - неявное или явное.

Три варианта:

  • Создайте компаратор следующим образом:

    elements.Sort(new Comparison<MyClass>(datatype.GetCompareFunction()));
    
  • Используйте лямбда-выражение для создания Comparison<T> и используйте его вместо:

    elements.Sort((x, y) => datatype.GetCompareFunction()(x, y));
    
  • Напишите реализацию IComparer<MyClass>, которая выполняет сравнение на основе CMPFN

Обратите внимание, что второй подход будет вызывать GetCompareFunction один раз для сравнения.

Гораздо лучшее решение - полностью избавиться от CMPFN - почему бы просто не использовать (или не внедрять) IComparer<MyClass> для начала? Обратите внимание, что это также уберет приведения. (Если вы довольны использованием делегатов вместо интерфейсов, вы можете вместо этого выразить сравнение как Comparison<MyClass>.)

Обратите внимание, что в .NET 4.5 вы можете использовать Comparer.Create для создания Comparer<T> из Comparison<T> делегата.

Я не уверен, почему ваш текущий API соответствует object, но вы должны знать, что в C # 3 и более ранних версиях (или C # 4 для .NET 3.5 и более ранних) вы не сможете конвертировать IComparer<object> в IComparer<MyClass> (через преобразование ссылок, в любом случае). Начиная с C # 4, вы можете из-за общей контравариантности.

1 голос
/ 09 июля 2010

Существует несколько перегрузок List<T>.Sort, но нет таких, которые принимают делегата с заданными вами параметрами (два объекта).

Однако существует перегрузка, которая принимает Сравнение делегата, с которым вы можете работать с вашим кодом с небольшими изменениями.По сути, вы просто заменяете своего CMPFN делегата на Comparison<MyClass> - в качестве дополнительного бонуса вы получаете строгую печать также в вашей функции SortStrings:

static private int SortStrings(MyClass a, MyClass b) {
    return a.GetValue().CompareTo(b.GetValue());
}

public Comparison<MyClass> GetCompareFunction() {
    return SortStrings; // or whatever
}

...

elements.Sort(datatype.GetCompareFunction()); 
1 голос
/ 09 июля 2010

Попробуйте что-то вроде этого

class AttributeSort : IComparer<AttributeClass >
    {
        #region IComparer Members

        public int Compare(AttributeClass x, AttributeClass y)
        {                
            if (x == null || y == null)
                throw new ArgumentException("At least one argument is null");

            if (x.attributeNo == y.attributeNo) return 0;
            if (x.attributeNo < y.attributeNo) return -1;
            return 1;
        }

        #endregion
    }

Вы можете назвать это тогда, как это

List<AttributeClass> listWithObj ....

listWithObj.Sort(new AttributeSort());

Должен работать так, как вы хотите. Вы также можете создать типобезопасный класс сравнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...