Есть ли способ заставить класс C# реализовывать определенные статические функции?

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

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

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

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

Ответов (9)

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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