Дополнительные Методы и его последствия в Разработке программного обеспечения (или это - действительно хорошая идея?) [закрытый]

Если Вы сделаете это программно в JS, то это будет похоже на перестраивание колеса. Я рекомендую использовать плагин jQuery, названный jGrowl

8
задан Daniel Daranas 26 July 2009 в 21:11
поделиться

7 ответов

Методы расширения не добавляются к типу. Это просто синтаксический сахар. Вы не можете получить доступ к личным данным. Метод расширения подобен любому статическому методу, который использует тип.

Худшее, что они могут сделать, - это нанести вред удобочитаемости и ввести людей в заблуждение. Помимо синтаксиса, они не существуют.

ОБНОВЛЕНИЕ (комментарий):

Это именно то, что я имел в виду под словами «вводить людей в заблуждение» и «вредить читабельности». К счастью, Visual Studio очень помогает различать методы расширения (используя значок в списке IntelliSense и всплывающую подсказку). Лично я Я немного предвзято против добавления кучи методов расширения к произвольным классам фреймворка (за исключением запечатанных классов, в которых методы расширения могут иметь большой смысл), если они не обеспечивают существенного выгода для конкретного проекта. Я предпочитаю хранить методы расширения в основном для интерфейсов и классов на верхних уровнях иерархии наследования. Это заставит разработчиков использовать их только там, где они применимы ко многим случаям во фреймворке, вместо того, чтобы делать какой-либо служебный метод расширением (IMO, это прямой артефакт автообнаружения методов расширения во всем пространстве имен. Я действительно хочу, чтобы C # требовал от вас добавления директиву using в конкретном классе вместо автоматического импорта всех расширений в пространство имен ).

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

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

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

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

9
ответ дан 3 November 2019 в 14:03
поделиться

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

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

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

5
ответ дан 3 November 2019 в 14:03
поделиться

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

Вы должны понимать, что методы расширения просто способ сделать вызовы статических методов похожими на методы экземпляров, когда импортируется соответствующее пространство имен, содержащее методы расширения. В частности:

  • Он не добавляет методы к типу, поэтому он не делает стандартные библиотеки «нестандартными». Это просто означает, что если вы Если у вас есть доступные методы расширения, вам будет проще работать с этими библиотеками.
  • Там есть явная связь, определенная с помощью методов расширения: метод расширения объявляет, с каким типом он «расширяется». тип первого параметра. Это не композиция или агрегирование, но я не понимаю, почему это проблема. Если что-то полезно и на самом деле не ухудшает дизайн, имеет ли значение, является ли это частью традиционного объектно-ориентированного подхода?
  • Да, методы расширения переносимы между проектами. Как всегда, существуют правила того, что происходит, если два метода расширения с одинаковыми именами видны одновременно.

Методы расширения через интерфейсы очень хороши, они допускают простую цепочку методов и т. Д. Я бы предпочел видеть вызов метода расширения, чем явный статический вызов, как в Java:

// Explicit helper method call
Collections.sort(collection);
// With extensions, this could be:
collection.sort();

Однако есть несколько недостатков:

  • Это не позволяет производным типам более эффективно переопределять реализацию. Конечно, производный тип может объявлять метод с той же сигнатурой, но он будет использоваться только в том случае, если тип времени компиляции является подходящим.
  • Способ, которым методы расширения обнаруживаются в C #, вызывает боль. Я писал об этом в другом месте ...
  • Методы расширения недоступны при использовании динамической типизации.

В целом, я думаю, что они прекрасны - и при умеренном использовании они могут иметь большое значение. Я бы определенно не хотел использовать LINQ без них.

Конечно, производный тип может объявлять метод с той же сигнатурой, но он будет использоваться только в том случае, если тип времени компиляции является подходящим.
  • Способ, которым методы расширения обнаруживаются в C #, вызывает боль. Я писал об этом в другом месте ...
  • Методы расширения недоступны при использовании динамической типизации.
  • В целом, я думаю, что они прекрасны - и при умеренном использовании они могут иметь большое значение. Я бы определенно не хотел использовать LINQ без них.

    Конечно, производный тип может объявлять метод с той же сигнатурой, но он будет использоваться только в том случае, если тип времени компиляции является подходящим.
  • Способ, которым методы расширения обнаруживаются в C #, вызывает боль. Я писал об этом в другом месте ...
  • Методы расширения недоступны при использовании динамической типизации.
  • В целом, я думаю, что они прекрасны - и при умеренном использовании они могут иметь большое значение. Я бы определенно не хотел использовать LINQ без них.

    они прекрасны - и при умеренном использовании они могут иметь большое значение. Я бы определенно не хотел использовать LINQ без них.

    они прекрасны - и при умеренном использовании они могут иметь большое значение. Я бы определенно не хотел использовать LINQ без них.

    5
    ответ дан 3 November 2019 в 14:03
    поделиться

    Я считаю это удобным способом реализации паттерна декоратора. Методы расширения позволяют расширять тип, добавляя к нему методы. Конечно, они переносимы между проектами, если у вас есть классы расширения в отдельной сборке, которой вы можете поделиться.

    2
    ответ дан 3 November 2019 в 14:03
    поделиться

    Я хотел поднять небольшую проблему в связи с тем, что вы сказали. Методы расширения не позволяют добавлять методы в существующий класс. Они позволяют создать впечатление добавления метода к существующему классу. Различие неуловимое, но очень важное.

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

    1. Я не верю, что это правда. В стандартизации библиотеки ничего не изменилось. Люди, использующие ваши методы расширения, увидят расширение библиотеки. Изменяет он или нет стандарт библиотеки, во многом зависит от того, что вы делаете в своих методах.

    2. Это просто способ дополнить тип методами без изменения исходного контракта.

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

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

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

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

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

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

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

    1
    ответ дан 3 November 2019 в 14:03
    поделиться

    Вы можете отключить сигнал тревоги. Методы расширения лишь незначительно влияют на синтаксис и ничего больше. Вместо того чтобы писать:

    SomeClass.SomeStaticMethod(someVar, someArg);
    

    Вы пишете:

    someVar.SomeStaticMethod(someArg);
    

    Он просто меняет местами порядок и удаляет квалификатор имени класса. В остальном все идентично. Значение этого состоит в том, что вы можете ввести имя переменной, и IDE может предложить вам полезные методы в функции intellisense, и вы можете читать код слева направо, так что «вложенные» вызовы функций становятся гораздо более читаемыми.

    Все ваши опасения в равной степени применимы к статическим методам - ​​и поэтому не стоит о них беспокоиться.

    Обновление

    Методы расширения «притворяются, что творит чудеса»? Только если вы думаете, что замена синтаксиса - это волшебство!

    Более вероятно, что вы просто привыкли видеть вещи, написанные определенным образом, и поэтому для вас становится сюрпризом видеть их написанными «задом наперед». Но с точки зрения других языков, теперь все правильно.

    Некоторые языки допускают возможность записи любого метода, не являющегося экземпляром, с первым аргументом перед именем метода, и если вы опустите точку, тогда это будет изящный способ поддержки инфиксных операторов, таких как a + b , без необходимости делать что-либо особенное.

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

    trimmed = string.Trim(str);
    

    Это похоже на то, как это делает F #. В конце концов, метод экземпляра string можно рассматривать как имеющий первый параметр типа string . Обычно вы не думаете об этом как о параметре, но он работает почти так же, и есть преимущества унифицированного синтаксиса.

    Метод экземпляра имеет доступ к закрытым членам класса, в котором он определен, тогда как метод расширения - нет. Но тогда метод экземпляра в производном классе не имеет доступа к закрытым данным базового класса. И в любом случае, почему вызывающий должен заботиться об этом?

    Предостережения

    Я бы не хотел создавать впечатление, что любое использование методов расширения имеет смысл. Например, есть ли какие-либо веские причины для создания метода расширения для объекта или универсального метода расширения для неограниченного типа T ? Такие вещи будут предлагаться intellisense практически в любом контексте и станут чем-то вроде языковых расширений, например с .

    Then there ' s дебаты о том, должен ли метод расширения допускать, чтобы его первый аргумент был null . Лично я думаю, что это нормально, если имя метода ясно показывает это, поэтому я думаю, что string.IsNullOrEmpty будет подходящим методом расширения. Но другие настроены более воинственно, и меня это не волнует, поэтому я бы занял позицию «когда в Риме». Вот еще один пример:

    public static void DisposeIfNotNull(this IDisposable d)
    {
        if (d != null)
            d.Dispose();
    }
    

    Из названия ясно, что он включает проверку на null (в этом весь смысл).

    отношение. Вот еще один пример:

    public static void DisposeIfNotNull(this IDisposable d)
    {
        if (d != null)
            d.Dispose();
    }
    

    Из названия ясно, что он включает проверку на null (в этом весь смысл).

    отношение. Вот еще один пример:

    public static void DisposeIfNotNull(this IDisposable d)
    {
        if (d != null)
            d.Dispose();
    }
    

    Из названия ясно, что он включает проверку на null (в этом весь смысл).

    5
    ответ дан 3 November 2019 в 14:03
    поделиться

    Другие уже указывали на тот факт, что методы расширения не изменяют исходный тип, поэтому просто добавлю немного: имейте в виду, что методы расширения видны только после того, как вы импортируете определяющий пространство имен. Поэтому, если вы «добавляете» некоторые методы в строку, они становятся доступными только тогда, когда вы их явно запрашиваете. Другими словами, можно контролировать объем методов расширения. Может быть, не идеально, но, по крайней мере, они не появляются из ниоткуда, когда кто-то добавляет их в проект.

    1
    ответ дан 3 November 2019 в 14:03
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: