Подтвердить что ты не робот

Недостатки методов расширения?

Метод расширения - действительно полезная функция, в которую вы можете добавить много функций, которые вы хотите в любом классе. Но мне интересно, есть ли недостатки, которые могут вызвать проблемы для меня. Любые комментарии или предложения?

4b9b3361

Ответ 1

  • Способ импортирования методов расширения (т.е. целое пространство имен за раз) не является гранулярным. Вы не можете импортировать одно расширение из пространства имен, не получая все остальное.
  • Это не сразу видно из исходного кода, где определяется метод. Это также является преимуществом - это означает, что вы можете сделать свой код похожим на остальные методы этого типа, даже если вы не можете поместить его в одно и то же место по любой причине. Другими словами, код проще понять на высоком уровне, но сложнее с точки зрения того, что именно выполняется. Я бы сказал, что это верно и для LINQ в целом.
  • У вас могут быть только методы расширения, а не свойства, индексы, операторы, конструкторы и т.д.
  • Если вы расширяете сторонний класс и в более поздней версии вводите новый метод с той же подписью, вам нелегко будет узнать, что значение вашего кода вызова изменилось. Если новый метод очень похож на ваше расширение, но с незначительно разными граничными условиями (или что-то еще), это может привести к некоторым очень сложным ошибкам. Это вряд ли произойдет.

Ответ 2

Пара вещей:

  • Не всегда понятно, откуда идет метод расширения, если вы не находитесь внутри VS.NET
  • Методы расширения не могут быть разрешены путем отражения или динамического поиска С# 4.0.

Ответ 3

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

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

Обычно я использую методы расширения в качестве оболочек для своих классов или классов BCL и помещаю их в другое пространство имен. например Utils и Utils.Extensions. Таким образом, расширения не должны использоваться.

Ответ 4

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

  • Нет полиморфизма (хотя поддерживается перегрузка)

  • Вы можете впасть в беспорядок с двусмысленностью, если для типа источника конфликта конфликтуют два метода расширения (и ни один из них не квалифицируется как "лучше" ). Затем компилятор отказывается использовать либо... что означает, что добавление метода расширения в сборке A может нарушить * несвязанный код в сборке B. Я видел это пару раз...

  • Вы не можете использовать с С# 2.0, поэтому, если вы пишете библиотеку для С# 2.0, она не помогает

  • Он нуждается в [ExtensionAttribute] - поэтому, если вы пишете библиотеку для .NET 2.0, вы попадаете в рассол: если вы объявите свой собственный [ExtensionAttribute], он может конфликтовать с вызывающим .NET 3.5

Не поймите меня неправильно - я большой поклонник!

Возможно, вы, наверное, догадываетесь, что я в настоящее время пишу библиотеку, которая должна работать для С# 2.0 и .NET 2.0, и где (досадно) методы расширения были бы действительно полезны!

* = только для компилятора; код, который уже скомпилирован, будет прекрасным.

Ответ 5

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

Ответ 6

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

Ответ 7

Есть два разных сценария, где методы расширения вступают в игру:

  1. Если вы хотите расширить какой-либо класс, структуру интерфейса, полученную из внешней сборки, за исключением классов, которые не помечены как запечатанные, где у вас может быть возможность извлечь из этих классов и расширить их с помощью дополнительных методов, у вас есть только и я повторить только эту опцию. Запечатанные классы и структуры не могут быть унаследованы и указывать на интерфейсы меньше.
  2. Однако в вашей собственной сборке предоставление метода расширения для определенного класса, структуры или интерфейса является очень субъективным вопросом при проектировании. Если вы хотите быть щедрым на людей, которые будут использовать вашу сборку, вы можете создать очень маленькие интерфейсы в идеале с несколькими свойствами, а затем присоединить к ним целую кучу методов расширения. Вот пример:

    public interface IPointF{
        float X { get; }
        float Y { get; }
    }
    
    public struct PointF: IPointF{
        public PointF(float x, float y){
            X=x;Y=y;
        }
        public float X { get; private set; }
        public float Y { get; private set; }
    }
    
    public static class PointHelper{
        public static PointF ADD(this IPointF p, float val){
            return new PointF(p.x+val, p.y+val);
        }
    }
    

Таким образом, любой будущий пользователь может сэкономить много времени в кодировании, унаследовав IPoint.