Это вопрос о методах расширения C # и их философии проектирования, поэтому я думаю, что лучший способ ответить на этот вопрос - процитировать документацию MSDN о целях методов расширения :
Методы расширения позволяют вам «добавлять» методы к существующим типам, не создавая новый производный тип, не перекомпилируя или иным образом не изменяя исходный тип. Методы расширения представляют собой особый вид статического метода, но они вызываются так, как если бы они были методами экземпляра в расширенном типе. Для клиентского кода, написанного на C #, F # и Visual Basic, нет очевидной разницы между вызовом метода расширения и методами, которые фактически определены в типе.
...
В общем, мы рекомендуем вам применять методы расширения экономно и только тогда, когда это необходимо. Когда это возможно, клиентский код, который должен расширять существующий тип, должен делать это путем создания нового типа, производного от существующего типа. Для получения дополнительной информации см. Наследование.
При использовании метода расширения для расширения типа, исходный код которого вы не можете изменить, вы рискуете, что изменение в реализации типа приведет к поломке вашего метода расширения.
Если вы реализуете методы расширения для данного типа, помните следующее:
- Метод расширения никогда не будет вызван, если он имеет ту же сигнатуру, что и метод, определенный в типе.
- Методы расширения вводятся в область действия на уровне пространства имен. Например, если у вас есть несколько статических классов, которые содержат методы расширения в одном именованном пространстве имен
Extensions
, все они будут перенесены в область действия using Extensions;
директивой.
Подводя итог, можно сказать, что методы расширения предназначены для добавления методов экземпляра к определенному типу, даже если разработчики не могут сделать это напрямую. А поскольку методы экземпляра всегда будут переопределять методы расширения, если они есть (если они вызваны с использованием синтаксиса метода экземпляра), это следует делать только в том случае, если вы не можете напрямую добавить метод или расширить класс. *
Другими словами, метод расширения должен действовать точно так же, как и метод экземпляра, поскольку в конечном итоге он может быть создан методом экземпляра некоторым клиентом. И поскольку метод экземпляра должен выдавать, если объект, к которому он вызывается null
, так же, как и метод расширения.
* В качестве дополнительного примечания, именно с такой ситуацией столкнулись дизайнеры LINQ: когда был выпущен C # 3.0, уже были миллионы клиентов, которые использовали System.Collections.IEnumerable
и System.Collections.Generic.IEnumerable<T>
в своих коллекциях, и в foreach
циклах. Эти классы возвращаются IEnumerator
объекты , которые были только два метода Current
и MoveNext
, таким образом добавляя дополнительные необходимые методы , например, такие , как Count
, Any
и т.д., будет нарушать эти миллионы клиентов. Таким образом, чтобы обеспечить эту функциональность (особенно потому, что она может быть реализована с точки зрения Current
и MoveNext
с относительной простотой), они выпустили ее как методы расширения, которые можно применять к любым существующим в настоящее времяIEnumerable
экземпляр и может также быть реализован классами более эффективными способами. Если бы дизайнеры C # решили выпустить LINQ в первый же день, он был бы представлен как методы экземпляра IEnumerable
, и они, вероятно, разработали бы какую-то систему для обеспечения реализаций интерфейса этих методов по умолчанию.