Какой самый лучший (самый полезный) интерфейс из написанных вами?

Название в основном объясняет это. Какие интерфейсы вы написали, чем вы гордитесь и чем много пользуетесь. Я полагаю, что парни, написавшие IEnumerable<T> и не в последнюю очередь IQueryable<T>, после их создания остались довольны.

Похоже, это хороший кандидат на статус Community Wiki.

Jay Bazuzi 30.11.2008 22:23
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
1
1 131
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

I guess the guys that wrote IEnumerable … had a good feeling after creating [it].

Я не совсем уверен. Что касается интерфейсов, IEnumerable оказался провальным. Это очевидно из того факта, что IEnumerable<T>, его общий аналог, на самом деле предлагает полностью интерфейс разные. (Ну, «другой» - не очень хорошее слово; в основном, оно добавляет одноразовости и приуменьшает значение совершенно бесполезного метода Reset; однако этот метод, конечно, все еще присутствует.)

Кроме того, похожие языки, которые имеют похожие конструкции (на ум приходит Java), имеют гораздо лучшую, более расширяемую конструкцию для удовлетворения тех же потребностей (и даже больше). Например, итераторы Java могут быть расширены до двунаправленных или для изменения доступа (тогда как IEnumerable всегда доступен только для чтения).

Обновлено: Поскольку в комментариях так много противоречий, позвольте мне уточнить. Я не говорю, что IEnumerable (или IEnumerator) являются интерфейсами плохой. Они адекватные. Однако их можно было улучшить. По крайней мере, метод Reset кажется беспорядочным.

Terjet сказал, что он «использует [s] это все время» - и это в точности моя точка зрения! IEnumerable - это основной интерфейс всей платформы .NET. Это повсеместно. Без него не было бы .NET. Поэтому не слишком ли много просить об интерфейсе идеально?

«Адекватный» - это просто еще одно слово для обозначения неудач.

Возможно, я мог бы перефразировать свой вопрос, чтобы он касался IEnumerable <T> и IQueryable <T>. Я все еще думаю, что IEnumerable <T> очень полезен и успешен, потому что он так широко используется. (Я постоянно использую это)

terjetyl 30.11.2008 19:52

В каком смысле IEnumerable <T> - это «совершенно другой интерфейс»? Это точно так же, только общее. И тогда единственная разница между IEnumerator <T> и IEnumerator заключается в том, что IEnumerator <T> расширяет IDisposable, что полезно для блоков итераторов.

Jon Skeet 30.11.2008 20:38

(Конечно, помимо универсальности - и вы не можете винить дизайнеров IEnumerator в том, что универсальные шаблоны отсутствуют во фреймворке ...)

Jon Skeet 30.11.2008 20:39

Я также не согласен с расширяемой природой - многие итераторы просто не подходят для того, чтобы быть доступными для записи или двунаправленными, и как только вы действительно не можете полагаться на полностью реализованный интерфейс, эти полуобязательные члены становятся намного менее полезными. (Даже сброс в IEnumerator был ошибкой IMO.)

Jon Skeet 30.11.2008 20:47

@Jon: О разнице: см. Пояснение в моем сообщении. По сути, метод Reset был большой ошибкой. О расширяемости: я не могу говорить о Java, но C++ убедительно показывает, что итераторы могут быть реализованы лучше много.

Konrad Rudolph 30.11.2008 22:22

Он не «обесценивает» Reset - он просто наследует его от IEnumerator, потому что ему не нужно изменять подпись. В противном случае вы должны применить ту же логику к MoveNext (), что очень важно! Утилизация - единственная реальная разница. Что касается итераторов C++ ... несколько иначе, IMO.

Jon Skeet 30.11.2008 22:27

(Продолжение) Различия между универсальными шаблонами и шаблонами позволяют по-разному работать с идеями интерфейсов C++ и Java / C#. Я доволен IEnumerable <T> - кроме Reset, я думаю, что это хороший интерфейс.

Jon Skeet 30.11.2008 22:30

Почему Reset () - такая плохая идея?

Autodidact 30.11.2008 22:58

Во многих случаях это просто не имеет смысла - например, вы не можете сбросить поток данных, пришедший из сети (при условии, что вы не буферизовали все это).

Jon Skeet 30.11.2008 23:01

Я согласен с Конрадом в этом. Конечно, полезно иметь итератор с прямым доступом, такой как IEnumerable, но он ограничен тем, что вообще не поддерживает более сложные двунаправленные или произвольные. Меня не впечатляет IEnumerable <T> (хотя установка LINQ поверх него очень удобна)

jalf 30.11.2008 23:33

Возможны многие вещи (например, блоки итераторов). потому что IEnumerable настолько ограничен. Это не означает, что другие более сложные API-интерфейсы бесполезны - IList <T> и т. д. - но было бы сложно реализовать такие вещи, как LINQ и блоки итератора, поверх этих более сложных интерфейсов.

Jon Skeet 30.11.2008 23:46

Джон, я согласен с вами, что LINQ не будет работать (или даже не понадобится) другой итератор. Я не это сказал. В C++ также есть алгоритмы, которые работают только с итераторами вывода (что в основном является моделями IEnumerable).

Konrad Rudolph 01.12.2008 00:14

Так что должны быть разные интерфейсы для моделирования более способных итераторов - это нормально. Только не заставляйте меня генерировать исключения, потому что я не могу реализовать все - гораздо лучше иметь более простой интерфейс (например, IEnumerable). Короче говоря, я действительно не согласен с тем, чтобы назвать IEnumerable провалом.

Jon Skeet 01.12.2008 00:18

«IEnumerable <T> меня не впечатляет» - я тоже, но я не думаю, что он сам по себе впечатляет. Он минималистичен, что придает ему универсальность, что делает его широко применимым, и все приложения, рассматриваемые вместе, впечатляют.

Daniel Earwicker 01.12.2008 00:18

@ Джон, да. Конечно, я не предлагал набивать интерфейс IEnumerable большим количеством участников. Я просто не понимаю, как можно построить разумную иерархию поверх IEnumerable.

Konrad Rudolph 01.12.2008 00:36

@Earwicker: Я, с другой стороны, бы впечатлен скупым интерфейсом. Я большой поклонник простоты. Однако IEnumerable + IEnumerator не очень просты.

Konrad Rudolph 01.12.2008 00:39

@Konrad: есть другие интерфейсы, уже построенные на IEnumerable: IOrderedEnumerable, например, и IList и т. д. Другие интерфейсы также могут быть построены поверх IEnumerator, точно так же, как Java имеет ListEnumerator с дополнительной функциональностью. У меня такое чувство, что нам придется соглашаться, чтобы не соглашаться.

Jon Skeet 01.12.2008 09:29

И последнее: когда «адекватный» и «неудачный» стали синонимами? Два определения: адекватный: «достаточный для цели»; сбой: «событие, которое не достигает своей предполагаемой цели». Извините, но они просто нет одинаковые.

Jon Skeet 01.12.2008 09:58

Что бы вы удалили из IEnumerable + IEnumerator для упрощения? Большинство людей удалили бы Reset, но, безусловно, все остальное важно для концепции итерации. Он минимально отражает понятие прямого итератора.

Daniel Earwicker 01.12.2008 11:19

@Earwicker: Совершенно верно. Сброса там быть не должно, и IEnumerator должен в первую очередь иметь расширенный IDisposable, но это все, что я бы изменил. В частности, я предпочитаю .NET-модель MoveNext () / Current модели Java hasNext () / next (). По моему опыту, с ним легче работать.

Jon Skeet 01.12.2008 12:28
Ответ принят как подходящий

Я доволен дизайном интерфейса, лежащего в основе Нажмите LINQ. Это очень простой интерфейс, но с ним вы можете делать самые разные интересные вещи. Вот определение (по памяти, но, по крайней мере, будет довольно близко):

public interface IDataProducer<T>
{
    event Action<T> DataProduced;
    event Action EndOfData;
}

По сути, он позволяет наблюдателям «прослушивать» поток данных, а не «извлекать» из него, как работает IEnumerable.

Три интересных места:

  • Имя отстой. Я хочу переименовать его, и у меня есть хорошие отзывы, но имени в пока нет.
  • Обработчики событий не следуют стандартным соглашениям .NET о наличии аргументов отправителя / события. В данном случае это действительно не имеет особого смысла.
  • Многоадресный характер событий делает это идеальным для вычисления нескольких агрегатов и т. д. Все это предоставляется бесплатно.

Удобно, что он успешно работает с дисперсией в C# 4.0 (я недавно проверял CTP ;-p). Хорошая работа, мы не ошиблись и добавили в интерфейс метод «протолкнуть».

Marc Gravell 30.11.2008 23:04

Рассматривали ли вы последствия отказа от использования делегатов EventHandler для безопасности? например Если ваш код имеет полное доверие, то код с частичным доверием может зарегистрировать Environment.FailFast в качестве обработчика для IDataProducer <string> .DataProduced и запустить его в контексте полного доверия.

Greg Beech 01.12.2008 03:17

Я не думал об этом, но если они работают в контексте полного доверия, не могли бы они просто назвать это сами?

Jon Skeet 01.12.2008 04:30

@Greg: Подумав об этом в одночасье, я думаю, что могу понять, что вы имеете в виду. Думаю, я бы изменил это, если бы это когда-нибудь стало проблемой, но пока все в порядке.

Jon Skeet 01.12.2008 09:28

Собственно интерфейс? Или просто API? Я доволен тем, как сработал материал универсальный оператор (доступен здесь) - я регулярно вижу, как люди спрашивают об использовании операторов с дженериками, поэтому я рад, что это удобный ответ для многих людей. Это может быть немного проще в C# 4.0, но я очень сомневаюсь, что он будет таким же быстрым - DLR-дерево / динамический материал имеет накладные расходы.

Я также очень рад, что это было полезно в Push LINQ, о котором уже упоминал Джон ;-p

Как и Марк, я не уверен, действительно ли это имеет значение для этого вопроса, но я могу определенно подтвердить, что его общий операторский материал потрясающий :)

Jon Skeet 30.11.2008 23:32

Я работаю над системой проверки, которую планирую вскоре выпустить в сообщество. По сути, это реализация шаблона Спецификация.

Основной интерфейс спроектирован так, чтобы быть функциональным по своей природе:

public interface ICheckable<T>
{
    CheckResult Apply(T target);
}

CheckResult - это struct, представляющий значение трех состояний: Passed, Failed и Ignored. Все преобразования и перегрузки операторов используются для обработки его как значения Boolean.

Это позволяет валидаторам выражать «У меня нет мнения» вместо того, чтобы возвращать вводящее в заблуждение значение true (подумайте, что RangeValidator, указывающий, что пустое поле является допустимым, поэтому он хорошо работает с RequiredFieldValidator).

Композиция происходит естественно и выполняется с помощью статических классов а-ля Linq. Каждая точка в проверке является неявным And следующей операции:

public static ICheckable<T> Add<T>(this ICheckable<T> check, ICheckable<T> otherCheck)
{
    return new Check<T>(t => check.Apply(t) && otherCheck.Apply(t));
}

public static ICheckable<T> Either<T>(this ICheckable<T> check, ICheckable<T> firstCheck, ICheckable<T> secondCheck)
{
    return check.Add(t => firstCheck.Apply(t) || secondCheck.Apply(t));
}

public static ICheckable<T> Not<T>(this ICheckable<T> check, ICheckable<T> negatedCheck)
{
    return check.Add(t => !negatedCheck.Apply(t));
}

Методы расширения работают нормально:

public static ICheckable<int> Percentage(this ICheckable<int> check)
{
    return check.Add(n => n >= 0 && n <= 100);
}

public static ICheckable<T> GreaterThanOrEqualTo<T>(this ICheckable<T> check, T value) where T : IComparable<T>
{
    return check.Add(t => t.CompareTo(value) >= 0);
}

public static ICheckable<T> LessThanOrEqualTo<T>(this ICheckable<T> check, T value) where T : IComparable<T>
{
    return check.Add(t => t.CompareTo(value) <= 0);
}

public static ICheckable<T> Range<T>(this ICheckable<T> check, T minimum, T maximum) where T : IComparable<T>
{
    return check.GreaterThanOrEqualTo(minimum).LessThanOrEqualTo(maximum);
}

// RangeExcludeMinimum
// RangeExcludeMaximum
// RangeExclusive

Каждая операция включает в себя перегрузки, которые используют лямбду для проверки:

public static ICheckable<T> Add<T>(this ICheckable<T> check, Func<ICheckable<T>, ICheckable<T>> makeCheck)
{
    return check.Add(makeCheck(new IgnoredCheck<T>()));
}

Таким образом, вы можете использовать такой синтаксис:

ICheckable<int> check;

check.Add(i => i.Percentage().GreaterThan(50).Even());

По какой-то причине Apply не называется Check? Это то, чего я ожидал, исходя из результата и имени интерфейса.

Jon Skeet 30.11.2008 23:31

Ха-ха, хороший улов :-) Интерфейс изначально был ICheck <T>, но я переименовал его, чтобы отразить его отложенный характер. Я, наверное, реализую это предложение.

Bryan Watts 30.11.2008 23:42

Это интерфейс ActionScript 3, который был ядром нашего нового поведения Flash Player в as3.

public interface IDisposable {
  public function dispose():void;
}

Как и следовало ожидать, метод dispose должен закрыть все ресурсы и отбросить все ссылки на все, что возможно.

Программисты на C++ могут посмеяться над этим «инновационным» интерфейсом (что вполне справедливо), но as3 представил множество проблем, связанных с управлением памятью во Flash. Все эти проблемы являются «старой шляпой» для многих компилируемых языков, но программисты ActionScript только сейчас впервые сталкиваются с этими проблемами.

Да, это все еще язык со сборкой мусора. Но, что бы там ни было, «держаться за руки» гораздо меньше, чем в ActionScript 2, о чем свидетельствует необходимость в этом интерфейсе.

Для работы с MVP-шаблоном у меня есть несколько базовых интерфейсов фреймворка:

public interface IValidatable {
  bool IsValid { get; set; }
  void ShowValidationFailureMessage(string message);
}

public interface ISubmitable {
  event EventHandler Submit;
  void ShowSubmitFailureMessage(string message);
  void ShowSubmitSuccessMessage(string message);
}

public interface ICancelable {
  event EventHandler Cancel;
}

С помощью этих трех интерфейсов я могу написать докладчика, который имеет эти общие операции (которые охватывают в основном все операции с формами). Например:

public interface ILogin : IValidatable, ISubmitable, ICancelable {
  string Username { get; set; }
  string Password { get; set; }
}

Затем вы можете создать докладчика и убрать его.

Другие вопросы по теме