Когда использовать статические классы в C # [duplicate]

556

Здесь MSDN должен сказать в разделе Когда использовать статические классы:

static class CompanyInfo
{
    public static string GetCompanyName() { return "CompanyName"; }
    public static string GetCompanyAddress() { return "CompanyAddress"; }
    //...
}

Использовать статический класс как единицу организация методов не связанные с конкретными объектами. Кроме того, статический класс может реализация проще и быстрее потому что вам не нужно создавать объект, чтобы вызвать его методы. Полезно организовать методы внутри класса значимым образом, таких как методы класса Math в пространстве имен System.

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

  • 9
    Как новичку в C #, было бы полезно объяснить, почему это было помечено как двойной вопрос о синглтоне против статического класса и как они соотносятся друг с другом.
  • 1
    mr5, синглтон и статический класс - это одно и то же. Singleton - это шаблон проектирования, используемый в других языках для имитации класса Static, поскольку другие языки (например, Java) не имеют встроенных классов Static, поэтому для создания такого класса необходимо полагаться на шаблон проектирования Singleton. Класс Static - это класс, который не может быть создан и может использоваться напрямую (например, класс Console). tutorialspoint.com/design_pattern/singleton_pattern.htm если вы проверите это, вы увидите, что при использовании Singleton вы не создаете новый экземпляр ...
Показать ещё 2 комментария
Теги:
class
static

11 ответов

636
Лучший ответ

Я написал свои мысли о статических классах в предыдущем ответе "Переполнение стека": Класс с единственным методом - лучший подход?

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

Полиморфизм

Скажем, у нас есть метод UtilityClass.SomeMethod, который радостно гудит. Внезапно нам нужно немного изменить функциональность. Большая часть функциональности одна и та же, но мы должны изменить пару частей, тем не менее. Если бы это не был статический метод, мы могли бы сделать класс деривации и изменить содержание метода по мере необходимости. Поскольку это статический метод, мы не можем. Конечно, если нам просто нужно добавить функциональность до или после старого метода, мы можем создать новый класс и называть его старым, но это просто грубо.

Недостатки интерфейса

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

Тестирование

Это в основном идет рука об руку с упомянутыми выше проблемами интерфейса. Поскольку наша способность взаимозаменяемых реализаций очень ограничена, у нас также возникнет проблема с заменой производственного кода на тестовый код. Опять же, мы можем их обернуть, но это потребует от нас изменения больших частей нашего кода, чтобы иметь возможность принимать обертки вместо реальных объектов.

Создает blobs

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

Ползучесть параметра

Для начала этот маленький милый и невинный статический метод может принимать один параметр. По мере роста функциональности добавляется пара новых параметров. Вскоре добавляются дополнительные параметры, которые являются необязательными, поэтому мы создаем перегрузки метода (или просто добавляем значения по умолчанию на языках, которые их поддерживают). Вскоре у нас есть метод, который принимает 10 параметров. Только первые три действительно необходимы, параметры 4-7 являются необязательными. Но если параметр 6 указан, необходимо заполнить 7-9... Если бы мы создали класс с единственной целью сделать то, что сделал этот статический метод, мы могли бы решить это, взяв требуемые параметры в конструктор и позволяет пользователю устанавливать необязательные значения через свойства или методы для одновременного задания нескольких взаимозависимых значений. Кроме того, если метод вырос до такого уровня сложности, он, скорее всего, все равно должен быть в своем собственном классе.

Требование потребителей к созданию экземпляра классов без причины

Один из наиболее распространенных аргументов: зачем требовать, чтобы потребители нашего класса создавали экземпляр для вызова этого единственного метода, хотя впоследствии он не использовался для экземпляра? Создание экземпляра класса - очень дешевая операция на большинстве языков, поэтому скорость не является проблемой. Добавление лишней строки кода для потребителя - это низкая стоимость заложить основу для гораздо более удобного решения в будущем. И, наконец, если вы хотите избежать создания экземпляров, просто создайте одноэлементную оболочку своего класса, которая позволяет легко повторное использование, хотя это и делает требование о том, чтобы ваш класс не имел гражданства. Если он не является апатридом, вы все равно можете создавать статические методы-обертки, которые обрабатывают все, сохраняя при этом все преимущества в долгосрочной перспективе. Наконец, вы также можете создать класс, который скрывает экземпляр, как если бы он был синглом: MyWrapper.Instance - свойство, которое просто возвращает new MyClass();

Только ситы имеют дело с абсолютами

Конечно, есть исключения из моей неприязни к статическим методам. Истинные классы полезности, которые не представляют опасности для вздутия, являются отличными случаями для статических методов - например, System.Convert. Если ваш проект является одноразовым, без требований к будущему обслуживанию, общая архитектура действительно не очень важна - статическая или не статическая, на самом деле не имеет значения - скорость разработки, однако.

Стандарты, стандарты, стандарты!

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

  • 11
    Стив Йегге тоже написал об этом. Но его пост намного длиннее, чем здесь. Если вы все еще не уверены, попробуйте steve.yegge.googlepages.com/singleton-considered-stupid
  • 285
    Кто-нибудь когда-нибудь замечал, что утверждение «Только ситхи имеют дело с абсолютами» является абсолютным? Сожалею. Не мог с этим поделать
Показать ещё 15 комментариев
126

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

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

Большинство классов могут быть представлены как статическими, так и нестатическими, но когда вы сомневаетесь, вернитесь к своим корням ООП и попытайтесь подумать о том, что вы представляете. Это объект, который выполняет действие (автомобиль, который может ускоряться, замедляться, поворачиваться) или что-то более абстрактное (например, отображение вывода).

Свяжитесь со своим внутренним ООП, и вы никогда не ошибетесь!

  • 8
    «Вы должны быть бесформенными, бесформенными, как вода. Когда вы наливаете воду в чашку, она становится чашкой. Когда вы наливаете воду в бутылку, она становится бутылкой. Когда вы наливаете воду в чайник, он становится чайником. Вода может капать, и она может разбиться. Стань, как вода, мой друг ». - Брюс Ли
  • 3
    @Chef_Code Извините, я не мог понять - как ваша цитата относится к данному вопросу, если вы не возражаете, я спрашиваю?
Показать ещё 2 комментария
35

Для С# 3.0 методы расширения могут существовать только в статических классах верхнего уровня.

  • 10
    @GamesBrainiac: Мне кажется, что такой комментарий к шестилетнему (!!) ответу немного ... не нужен?
  • 0
    @DevSolar Это появилось в одной из тем обзора модов, так что я подумал, что я посмотрю на это: P
Показать ещё 1 комментарий
20

Если вы используете инструменты анализа кода (например, FxCop), рекомендуется пометить метод static, если этот метод не обращайтесь к данным экземпляра. Обоснование заключается в том, что есть выигрыш в производительности. MSDN: CA1822 - Отметить участников как статические.

Это скорее правило, чем правило, действительно...

  • 0
    Кроме того, такое статическое объявление для закрытого метода в классе экземпляра передает полезную дополнительную информацию разработчику. Он сообщает, что такой частный статический метод не изменяет состояние экземпляра. То есть метод является служебным методом в классе.
12

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

public static class Log
{
   private static readonly ILoggerFactory _loggerFactory =
      IoC.Resolve<ILoggerFactory>();

   public static ILogger For<T>(T instance)
   {
      return For(typeof(T));
   }

   public static ILogger For(Type type)
   {
      return _loggerFactory.GetLoggerFor(type);
   }
}

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

  • 0
    Почему вы определяете неиспользуемый параметр в универсальном методе?
  • 1
    @JohnClearZ может быть потому, что тогда вы можете вызвать For с существующим объектом и получить регистратор для него, не думая о фактическом типе объекта. Просто предположение.
Показать ещё 1 комментарий
9

Я начал использовать статические классы, когда хочу использовать функции, а не классы, как свою единицу повторного использования. Раньше я был все о зле статических классов. Однако изучение F # заставило меня увидеть их в новом свете.

Что я имею в виду? Ну, скажем, при разработке какого-то супер DRY кода я получаю кучу классов одного метода. Я могу просто привести эти методы в статический класс, а затем применить их к зависимостям с помощью делегата. Это также прекрасно сочетается с моим контейнером зависимой инъекции (DI) Autofac.

Конечно, прямая зависимость от статического метода все еще обычно зла (есть некоторые незломысленные виды использования).

8

Статические классы очень полезны и имеют место, например библиотеки.

Лучшим примером, который я могу предоставить, является класс .Net Math, статический класс пространства имен System, который содержит библиотеку математических функций.

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

Пустой отказ от статических классов как неправильный, не использовать их или сказать, что "может быть только один" или нет, так же неправильно, как и при использовании их.

С#.Net содержит ряд статических классов, которые используются так же, как класс Math.

Поэтому, учитывая правильную реализацию, они чрезвычайно полезны.

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

  • 1
    Ответ, говорящий «может быть только один», говорит не о количестве статических классов, а довольно мило (хотя довольно неправильно), ссылаясь на тот факт, что может быть только один экземпляр (неправильный, потому что на самом деле может быть только ноль экземпляров). )
  • 0
    Ах, спасибо Кирк, отсюда мое замешательство; в любом случае, просто отвергая статичность или просто заявляя, что шаблон синглтона лучше (как я видел), я считаю очень ценным инструментом из набора инструментов.
Показать ещё 1 комментарий
8

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

Кроме этого, я думаю, что "Использовать статический класс как единицу организации для методов, не связанных с конкретными объектами". достаточно хорошо описывают их предполагаемое использование.

7

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

Я просто добавлю свои 2 цента к этому, сказав, что я создаю класс static, когда этот класс является чем-то уникальным в системе, и это действительно бессмысленно иметь какие-либо его экземпляры в программе, Тем не менее, я резервирую это использование для больших классов. Я никогда не объявляю такие маленькие классы, как в примере MSDN, как "статические" и, конечно же, не классы, которые будут членами других классов.

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

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

2

На основе MSDN:

  • Вы не можете создать экземпляр для статических классов
  • Если класс, объявленный как статический, переменная-член должна быть статичной для этого класса
  • Запечатанный [Не удается унаследовать]
  • Невозможно содержать конструктор экземпляра
  • Управление памятью

Пример: математические вычисления (математические значения) не изменяются [СТАНДАРТНЫЙ РАСЧЕТ ДЛЯ ОПРЕДЕЛЕННЫХ ЗНАЧЕНИЙ]

  • 14
    Вы просто описываю то , что статический класс, вместо описания , когда они будут практичны, или какова их цель.
  • 1
    Вопрос в том, когда использовать статический класс, а не в том, что вы можете делать со статическим классом.
2

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

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

  • 4
    Я бы предпочел не использовать методы расширения для вспомогательных методов. Методы расширения являются запутанными, запутанными для других разработчиков и, как правило, не интуитивно понятны для других языков. Методы расширения имеют свое назначение, но не как универсальные вспомогательные методы imho.
  • 2
    Просто для пояснения, под вспомогательным методом я имею в виду что-то вроде: string.ToSentence () или string.Camelize (). По сути, все, что будет жить в классе, как StringHelpers.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню