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

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

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

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

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

Ответ 1

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

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

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

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

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

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

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

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

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

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

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

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

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

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

Ответ 9

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

  • Определите методы в интерфейсе.
  • Объявить методы с абстрактными.
  • Реализовать общедоступные статические методы и переопределить абстрактный метод просто вызвать статические методы.

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