Есть ли способ заставить класс C # реализовать определенные статические функции? - PullRequest
31 голосов
/ 23 февраля 2009

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

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

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

Ed Удалено слово «интерфейс», чтобы избежать путаницы.

Ответы [ 9 ]

30 голосов
/ 23 февраля 2009

Нет, в C # для этого нет языковой поддержки. Есть два обходных пути, о которых я могу сразу подумать:

  • использовать отражение во время выполнения; скрещенные пальцы и надежда ...
  • использовать singleton / default-instance / аналог для реализации интерфейса, который объявляет методы

( обновление )

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

18 голосов
/ 23 февраля 2009

Нет. По сути, это звучит так, будто вы после своего рода «статического полиморфизма». Этого не существует в C #, хотя я предложил своего рода понятие «статический интерфейс», которое может быть полезно с точки зрения обобщений .

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

6 голосов
/ 23 июля 2009

Это отличный вопрос, с которым я столкнулся в своих проектах.

Некоторые считают, что интерфейсы и абстрактные классы существуют только для полиморфизма, а не для принуждения типов к реализации определенных методов. Лично я считаю полиморфизм первичным вариантом использования, а принудительную реализацию - вторичным. Я использую технику принудительной реализации довольно часто. Как правило, это появляется в коде платформы, реализующем шаблон шаблона. Базовый / шаблонный класс заключает в себе некоторую сложную идею, а подклассы предоставляют многочисленные варианты, реализуя абстрактные методы. Одним из прагматических преимуществ является то, что абстрактные методы обеспечивают руководство для других разработчиков, реализующих подклассы. Visual Studio даже может отключить методы для вас. Это особенно полезно, когда разработчику технического обслуживания необходимо добавить новый подкласс спустя месяцы или годы.

Недостатком является то, что в C # нет конкретной поддержки для некоторых из этих шаблонных сценариев. Статические методы - это одно. Еще один конструктор; в идеале ISerializable должен заставить разработчика реализовать конструктор защищенной сериализации.

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

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

4 голосов
/ 23 февраля 2009

К сожалению, нет, в языке нет ничего подобного.

3 голосов
/ 23 февраля 2009

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

1 голос
/ 26 июня 2009

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

У меня есть класс (назовем его «Виджет»), который наследуется от класса в стороннем ORM. Если я создаю экземпляр объекта Widget (следовательно, создаю строку в БД) просто для того, чтобы убедиться, что мои статические методы объявлены, я создаю большую проблему, чем та, которую пытаюсь убрать.

Если я создаю этот дополнительный объект в хранилище данных, я должен скрыть его от пользователей, расчетов и т. Д.

Я использую интерфейсы в C #, чтобы убедиться, что я реализую общие функции в наборе классов.

Для некоторых методов, реализующих эти функции, требуются данные экземпляра. Я кодирую эти методы как методы экземпляра и использую интерфейс C #, чтобы убедиться, что они существуют в классе.

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

0 голосов
/ 05 ноября 2011

Если вы только что получили эти ошибки компилятора, рассмотрите следующую настройку:

  1. Определение методов в интерфейсе.
  2. Объявите методы с абстрактным.
  3. Реализуйте открытые статические методы, и переопределения абстрактного метода просто вызывают статические методы.

Это немного лишний код, но вы будете знать, когда кто-то не реализует требуемый метод.

0 голосов
/ 23 февраля 2009

Подход, который приближает вас к тому, что вам нужно, - это синглтон, как предположил Марк Гравелл.

Интерфейсы, помимо прочего, позволяют вам обеспечить некоторый уровень абстракции для ваших классов, чтобы вы могли использовать данный API независимо от типа, который его реализует. Однако, поскольку вам НЕОБХОДИМО знать тип статического класса, чтобы использовать его, зачем вам применять этот класс для реализации набора функций?

Может быть, вы могли бы использовать пользовательский атрибут, такой как [ImplementsXXXInterface], и ​​обеспечить некоторую проверку во время выполнения, чтобы убедиться, что классы с этим атрибутом действительно реализуют необходимый вам интерфейс?

0 голосов
/ 23 февраля 2009

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

...