Почему бы не разрешить реализацию интерфейса на месте в .NET?

Либо я что-то упускаю, либо .NET не поддерживает то, что делает Jave. Я бы хотел, чтобы избежать создания небольшого класса только ради реализации небольшого интерфейса. Например, метод LINQ Except ожидает IEqualityComparer. Поэтому мне пришлось написать небольшой класс, который реализует интерфейс. Однако в Java я могу просто сделать new IEqualityComparer() { //interface declarations } и сделать с ним. Так в чем проблема?

Это относится к этому сообщению Может ли анонимный класс С# реализовать интерфейс?.

Сложение: На данный момент я добавил переопределения для Equals и GetHashCode.

Ответы

Ответ 1

Вы правы, С#, в отличие от Java, не поддерживает понятие анонимных внутренних классов, которые могут реализовывать интерфейсы. Я столкнулся с той же проблемой с IEqualityComparer и в итоге пришел к следующему решению.

public static class Utils {
  private sealed class EqualityComparer<T> : IEqualityComparer<T> {
    private readonly Func<T, T, bool> m_equals;
    private readonly Func<T, int> m_getHashCode;
    internal EqualityComparer(
      Func<T, T, bool> equals,
      Func<T, int> getHashCode) {
      m_equals = equals;
      m_getHashCode = getHashCode;
    }
    public bool Equals(T left, T right) {
      return m_equals(left, right);
    }
    public int GetHashCode(T value) {
      return m_getHasheCode(value);
    }
  }

  public static IEqualityComparer<T> CreateEqualityComparer<T>(
    Func<T, T, bool> equals, 
    Func<T, int> getHashCode) {
    return new EqualityComparer<T>(equals, getHashCode);
  }
}

Теперь в местах, где я хочу "на лету" IEqualityComparer<T>, я могу просто сделать следующее

var comparer = Utils.CreateEqualityComparer<Student>(
  (left, right) => left.Name == right.Name,
  value => value.Name.GetHashCode());

Ответ 2

Короткий ответ заключается в том, что это не поддерживается в С#.Net

Я должен признать, что это звучит довольно аккуратно, но обычно это действительно не нужно. Методы сравнения в Linq кажутся исключением, большинство других методов Linq принимают перегрузки, которые выполняют одну и ту же функцию с помощью делегатов, которые могут быть реализованы "на месте" с помощью лямбда-выражений.

В этом конкретном примере есть рассеяние сообщений в блогах, в которых есть реализация для LambdaComparer (или аналогичного), которая позволяет делать именно это, хотя и использует несколько менее элегантный синтаксис. См. Передайте выражение лямбда вместо IComparer или IEqualityComparer или любого интерфейса одного метода? для примера.