Почему C# не позволяет статическим методам реализовать интерфейс?

Почему C# был разработан таким образом?

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

Если классы хотят реализовать это поведение в общем методе, почему бы и нет?

Вот пример того, что я имею в виду:

// These items will be displayed in a list on the screen.
public interface IListItem {
  string ScreenName();
  ...
}

public class Animal: IListItem {
    // All animals will be called "Animal".
    public static string ScreenName() {
        return "Animal";
    }
....
}

public class Person: IListItem {

    private string name;

    // All persons will be called by their individual names.
    public string ScreenName() {
        return name;
    }

    ....

 }

Что ж, в Java 8 он есть (stackoverflow.com/questions/23148471/…).

liang 11.07.2015 07:12

Посмотрите, как можно объединить статическое поведение с наследованием или реализацией интерфейса: stackoverflow.com/a/13567309/880990

Olivier Jacot-Descombes 30.07.2016 17:19
IListItem.ScreenName() => ScreenName() (с использованием синтаксиса C# 7) явно реализует метод интерфейса, вызывая статический метод. Однако все становится уродливым, когда вы добавляете к этому наследование (вам нужно переопределить интерфейс)
Jeroen Mostert 18.04.2017 17:34

Просто сообщаю всем, что ожидание подошло к концу! В C# 8.0 есть методы статического интерфейса: dotnetfiddle.net/Lrzy6y (хотя они работают немного иначе, чем OP хотел, чтобы они работали - вам не нужно их реализовывать)

Jamie Twells 21.11.2019 23:08
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
458
4
187 567
25
Перейти к ответу Данный вопрос помечен как решенный

Ответы 25

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

Думаю, близорукость.

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

IMyInterface val = GetObjectImplementingIMyInterface();
val.SomeThingDefinedinInterface();

Только с введением интерфейсов, поскольку ограничения для дженериков, добавление статического метода к интерфейсу имело практическое применение.

(отвечает на комментарий :) Я считаю, что для его изменения сейчас потребуется изменение CLR, что приведет к несовместимости с существующими сборками.

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

Kramii 03.11.2008 19:05

я тоже сталкиваюсь с этим при реализации универсального класса, который требует, чтобы тип параметра создавался сам с некоторыми параметрами. Поскольку new () не может принимать никаких. Ты уже придумал, как это сделать, Крами?

Tom 09.12.2009 21:31

@Kramii: контракты на статические API. Мне не нужен экземпляр объекта, просто гарантия конкретной подписи, например. IMatrixMultiplier или ICustomSerializer. Funcs / Actions / Delegates в качестве членов класса делают трюк, но IMO это иногда кажется излишним и может сбивать с толку неопытных, пытающихся расширить API.

David Cuccia 10.05.2010 02:04

Интерфейсы определяют поведение объекта.

Статические методы не определяют поведение объекта, но поведение, которое каким-то образом влияет на объект.

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

Scott Langham 03.11.2008 20:27

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

Scott Langham 03.11.2008 20:28

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

Jeff Yates 03.11.2008 21:03

Что ж, да, вам бы пришлось исказить голову, чтобы определить метод, который не соответствовал бы его названию. Однако, если у вас есть IAlertService.GetAssistance (), его поведение может заключаться в том, чтобы мигать светом, подавать сигнал тревоги или тыкать палкой в ​​глаз.

Scott Langham 04.11.2008 03:05

Реализация также сможет записывать в файл журнала. Это поведение не указано в интерфейсе. Но, может быть, ты прав. Следует действительно уважать поведение «получить помощь».

Scott Langham 04.11.2008 03:09

Рассмотрим это с точки зрения языковой независимости: интерфейсы - это абстрактные типы. Типы - это то, что описывает экземпляр или значение. Статические классы не являются истинными типами, говоря теоретически, поскольку они не могут быть созданы. Из этого следует, что статические классы должны / не могут иметь интерфейсы.

awdz9nld 07.11.2012 23:52

@ScottLangham Я смотрю на эти "именованные операции" как на поведение. То, как класс реализует это поведение, не имеет значения. В приведенном выше примере GetAssistance () - это поведение. Как это происходит, меня это не касается; и в этом все дело. Классы бесполезны без поведения; если только они не являются простыми пакетами данных.

John Kraft 25.02.2013 19:17

Это старый ответ на старый вопрос, но вот почему я проголосовал против: если бы интерфейсы могли обеспечивать определенное поведение, они были бы не столь полезны. Одна из наиболее частых причин для интерфейсов - позволить нескольким дочерним классам реализовывать различное поведение для одного и того же контракта (например, interface IStore => для памяти, для диска, для базы данных, для NULL и т. д.). Разработчик интерфейса может (и должен) задокументировать «ожидаемое» поведение и, по крайней мере, предположения в комментариях к документу, но интерфейс не может обеспечить его соблюдение. В частности, в C# нельзя даже ограничивать исключения.

Scott Gartner 20.06.2017 22:44

Как и большинство людей, которые на протяжении многих лет голосовали против этого, вы путаете поведение с реализацией. Если использовать пример с глупым животным / собакой, Лай - это поведение. Интерфейс обеспечивает поведение Bark, а не реализацию такого поведения. Контракт / интерфейс определяет поведение. Интерфейсы не позволяют реализовать различное поведение, они позволяют реализовать поведение по-разному. Лай есть лай независимо от породы. Здесь все семантика и педантика.

John Kraft 12.07.2017 00:13
Ответ принят как подходящий

Предполагая, что вы спрашиваете, почему вы не можете этого сделать:

public interface IFoo {
    void Bar();
}

public class Foo: IFoo {
    public static void Bar() {}
}

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


To implement your example, I would give Animal a const property, which would still allow it to be accessed from a static context, and return that value in the implementation.
public class Animal: IListItem {
    /* Can be tough to come up with a different, yet meaningful name!
     * A different casing convention, like Java has, would help here.
     */
    public const string AnimalScreenName = "Animal";
    public string ScreenName(){ return AnimalScreenName; }
}

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

Прекрасный пример! Но я не уверен, что понимаю ваши рассуждения. Несомненно, компилятор мог был разработан, чтобы смотреть и на члены statuc? Разве у экземпляров нет таблицы адресов для реализации этих методов? Нельзя ли включить в эту таблицу статические методы?

Kramii 03.11.2008 19:03

Я понял, когда собирался прояснить, что то, о чем вы просите, безусловно, может быть реализовано компилятором. Итак, я изменил свой ответ на лучший ответ "Почему?"

Chris Marasti-Georg 03.11.2008 19:05

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

oleks 16.02.2011 16:23

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

Chris Marasti-Georg 22.02.2011 20:10

Многие люди взвесили обе стороны: от «Это не имеет смысла» до «Это ошибка, я бы хотел, чтобы ты мог». (Я думаю, что для него есть допустимые варианты использования, именно так я и оказался здесь.) В качестве обходного пути метод экземпляра может просто делегировать статическому методу.

harpo 31.03.2011 22:27

Вы также можете просто реализовать этот фрагмент как метод расширения в базовом интерфейсе, например: public static object MethodName(this IBaseClass base) внутри статического класса. Обратной стороной, однако, является то, что в отличие от наследования интерфейса - это не заставляет / не позволяет отдельным наследникам хорошо переопределять методологию.

Troy Alford 03.11.2012 04:26

Это имело бы смысл с дженериками. Например, void Something <T> (), где T: ISomeInterface {new T (). DoSomething1 (); T.DoSomething2 (); }

Francisco Ryan Tolmasky I 18.12.2013 14:06

Привет. Я приезжаю два года спустя, чтобы спросить об этом: «Методы, указанные в интерфейсе, должны быть там, чтобы определять контракт для взаимодействия с объектом». Это почему? Почему взаимодействовать только с объектом? Если это правда, то рассуждения C# прекрасны, но почему это правда?

Blueriver 29.10.2015 10:34

@harpo: Было бы полезно, если бы .NET позволяла расширять существующие интерфейсы новыми членами, при этом система автоматически генерирует для любого отсутствующего члена реализации простой метод «по умолчанию», который привязывается к одному из двух подходящих названий и тегов. статический метод в интерфейсе (если они существуют) с «дополнительным» первым параметром типа T для реализаций классов или ref T для реализаций структур. Эффективность некоторых интерфейсов, таких как IEnumerable<T>, можно значительно повысить, добавив такие элементы, как int Move(int), для перемещения более чем одного элемента за раз.

supercat 01.09.2016 22:29

@supercat вы описываете методы расширения?

Chris Marasti-Georg 13.09.2016 23:42

@ ChrisMarasti-Georg: Методы расширения - это синтаксический сахар времени компиляции; что-то вроде SomeEnumerable.Count() превращается в Enumerator.Count(SomeIEnumerable), если компилятор знает о последнем методе расширения. То, что я описываю, позволило бы добавить что-то вроде bool Move(ref int) в качестве фактического члена IEnumerable<T>, при этом Среда выполнения .NET использует атрибуты, прикрепленные к этому интерфейсу, для автоматического создания реализации, такой как bool Move(ref int n) { return IEnumerable<T>.Move(this, ref n); };. Классы, которые могут поддерживать быстрый переход по N (как List<T>.Enumerator ...

supercat 13.09.2016 23:54

... вероятно, мог бы) обрабатывать перемещение N-элементов за один шаг, но те, которые не запрограммированы для этой способности, могут обрабатываться статическим методом, который просто вызывает MoveNext соответствующее количество раз. Обратите внимание, что если использовать Append для присоединения к пройденному List<T> из 1000000 элементов с итератором из 12 элементов, попытка пропустить вперед 1 000 0005 элементов может быть эффективно обработана путем создания перечислителя List<T> с просьбой переместить 1 000 005 шагов и найти выяснилось, что не хватило 5 элементов, а затем попросил итератор продвинуть 5 элементов. Намного лучше, чем звонить ...

supercat 13.09.2016 23:58

... MoveNext на List<T>.Enumerator 1000000 раз.

supercat 13.09.2016 23:58

@Blueriver Мне интересно то же самое. И я не уверен, что рассуждения Криса в этом ответе правильны. На мой взгляд, интерфейсы определяют коммуникационный контракт для `` типа '', а не для отдельных объектов, поэтому, учитывая это, на этой планете в этой вселенной нет абсолютно никаких причин, по которым нельзя было бы реализовать свойство / метод как статический. К сожалению, вы не можете использовать C# или, по крайней мере, не так легко, как показали другие. Это заняло у меня много времени, но думаю, я наконец нашел то, что я считаю недостатком C#.

Ash 24.11.2017 03:07

@Ash Я понимаю, что многие люди умнее меня сказали, что это технически осуществимо, и только не в C# и тому подобном, но ... Есть ли на самом деле какой-либо вариант использования, кроме «Один из этих методов, который я реализовано / переопределено из базового класса / интерфейса, я бы также хотел выставить в статическом контексте то же имя »? В некоторых случаях это незначительное неудобство (дайте статическому методу другое имя и делегируйте ему нестатическую версию) и хорошо, недостаток. Какой еще вариант использования есть? Кроме того, я считаю, что ответ Марка должен быть принятым, а не моим.

Chris Marasti-Georg 28.11.2017 21:39

@Chris Для моего конкретного случая использования это означает, что я должен использовать синглтон ... но это при условии, что потребитель действительно использует экземпляр синглтона; нет ограничений на огромное количество создаваемых экземпляров, по одному на каждый раз, когда требуется определенная функциональность, которая просто одинакова для всех экземпляров, но мы не можем обеспечить статичность в контракте, поэтому ...

Ash 06.12.2017 09:17

@Ash правильно реализованный одноэлементный шаблон не позволяет создавать несколько экземпляров. Я бы использовал внедрение зависимостей и управлял бы жизненным циклом объекта через контейнер.

Chris Marasti-Georg 06.12.2017 19:26

Я не могу согласиться с тем, что использование статического метода в интерфейсе - это плохой дизайн по своей сути.

Mashmagar 14.02.2019 16:25

То, что вы, кажется, хотите, позволит вызывать статический метод как через Type, так и через любой экземпляр этого типа. Это, по крайней мере, приведет к двусмысленности, что не является желательной чертой.

Будут бесконечные споры о том, имеет ли это значение, что является наилучшей практикой и есть ли проблемы с производительностью, связанные с этим так или иначе. Просто не поддерживая его, C# избавляет нас от необходимости беспокоиться об этом.

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

Интересно, что вполне возможно вызвать статический метод с помощью обоих экземпляров типа объявления в VB.Net (хотя в последнем случае IDE выдает предупреждение). Кажется, это не проблема. Возможно, вы правы насчет оптимизации.

Kramii 03.11.2008 19:54

Интерфейсы - это абстрактные наборы определенных доступных функций.

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

Если бы методы были определены как статические, класс, реализующий интерфейс, не был бы так инкапсулирован, как мог бы. Инкапсуляция - это хорошая вещь, к которой нужно стремиться в объектно-ориентированном дизайне (я не буду вдаваться в подробности, вы можете прочитать это здесь: http://en.wikipedia.org/wiki/Object-oriated). По этой причине статические методы не разрешены в интерфейсах.

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

Kramii 03.11.2008 19:50

Вы не можете использовать ключевое слово static. Однако нет никаких ограничений, потому что вам не нужно ключевое слово static для написания метода, который ведет себя статически. Просто напишите метод, который не обращается ни к одному из членов своего объекта, тогда он будет вести себя так же, как статический метод. Итак, ограничение есть.

Scott Langham 03.11.2008 20:06

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

Chris Marasti-Georg 03.11.2008 20:41

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

Scott Langham 04.11.2008 02:46

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

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

Это интересная точка зрения, и, вероятно, именно это и имели в виду дизайнеры C#. С этого момента я буду думать о статических членах по-другому.

Kramii 03.11.2008 20:00

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

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

По политическим соображениям я буду цитата Эрика Липперта (который хорошо разбирается в компиляторах и имеет степень бакалавра математики, информатики и прикладной математики Университета Ватерлоо (источник: LinkedIn):

...the core design principle of static methods, the principle that gives them their name...[is]...it can always be determined exactly, at compile time, what method will be called. That is, the method can be resolved solely by static analysis of the code.

Обратите внимание, что Липперт оставляет место для так называемого метода типа:

That is, a method associated with a type (like a static), which does not take a non-nullable “this” argument (unlike an instance or virtual), but one where the method called would depend on the constructed type of T (unlike a static, which must be determinable at compile time).

но еще предстоит убедиться в его полезности.

Отлично, это ответ, который я хотел написать - я просто не знал деталей реализации.

Chris Marasti-Georg 03.11.2008 20:44

Отличный ответ. И я хочу этот «типовой метод»! Было бы полезно во многих случаях (подумайте о метаданных для типа / класса).

Philip Daubmeier 18.04.2012 18:22

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

Ian Boyd 11.06.2012 21:18

В C# - нельзя ли это реализовать как public static object Method<T>(this T t)? Или я забываю, что существует определенное ограничение C# на этот метод расширения?

Troy Alford 03.11.2012 04:28

+1 за то, что действительно ответил на вопрос, а не за педантизм и сопливость. Как сказал Ян Бойд: «Это неплохой дизайн - это техническое ограничение».

Joshua Pech 30.03.2013 19:23

Так же, как теоретическая мысль: почему компилятор не может неявно сгенерировать класс (с vtable!) Для каждого типа, который статически реализует интерфейс, пусть методы этого класса перенаправляют все вызовы статическим методам и вставляют экземпляр этого класса всякий раз, когда тип приводится к типу интерфейса (например, назначается переменной этого типа интерфейса)?

O. R. Mapper 30.01.2014 01:10

Кроме того, я не уверен, что вижу полное обоснование в первой цитате: когда методы вызываются «как статические методы» (class.method), метод является по-прежнему разрешается исключительно путем статического анализа кода. Разве эта тема не о том, что вызывается при вызове методов интерфейс, которые обычно точно известны во время компиляции?

O. R. Mapper 30.01.2014 01:12

Вполне возможно сгенерировать объект для статического класса со связанной vtable. Посмотрите, как Scala обрабатывает object и как им разрешено реализовывать интерфейсы.

Sebastian Graf 08.05.2014 23:45

@Sebastian - я подхожу к опасной близости к тому, чтобы превзойти мои знания о компиляторе, но поскольку C# использует этот термин (в соответствии с другими языками на основе C), определение статического метода отправляется статически. Это исключает vtable (которая будет динамически отправляться). Объекты Scala на самом деле не статичны - это просто обычный класс, реализованный как синглтон (с vtable и связанными с ней плюсами и минусами).

Mark Brackett 09.05.2014 17:22

Таблица vtable может просто указывать на статическую реализацию, как и Func<>, но вместо одного указателя она содержит все указатели на методы, требуемые интерфейсом. Использование static, как в статической диспетчеризации, искусственно ограничивает язык ради «объектной ориентации».

Sebastian Graf 10.05.2014 01:13

Большинство объектно-ориентированных языков имеют тенденцию быть слишком строгими по отношению к диспетчеризации: если тип объекта во время выполнения известен, то нет абсолютно никакого смысла извлекать фактический метод через доступ к vtable (это сделало бы дешевую оптимизацию компилятора). С другой стороны, утверждение, что статически отправляемый метод (либо static, либо просто не-virtual) не может удовлетворить интерфейс, в равной степени бессмысленно, потому что для удовлетворения интерфейса все, что требуется, - это vtable для сопоставления с реализуемыми методами. Вот где все ОО-языки типа C идут не так. Думаю, оглядываясь назад, легко сказать. / rant

Sebastian Graf 10.05.2014 01:22

tldr; статическая и динамическая отправка не должна зависеть от объявления метода, а от использования, как это сделано в классах типов Go, Rust и Haskell.

Sebastian Graf 10.05.2014 01:26

с полиморфным экземпляром должна быть возможность определить контракт статического типа параметрического типа-параметра, а затем вызвать эти статические методы.

David Jeske 24.10.2014 09:32

@IanBoyd Я думаю, что «плохой дизайн» - это то, что имеет вызванный техническое ограничение. Другими словами, если бы фреймворк был спроектирован иначе, этого технического ограничения не существовало бы.

DCShannon 30.12.2014 07:03

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

William Jockusch 19.03.2015 18:23

Все эти разговоры о плохом дизайне / технических ограничениях - это как бы упущение сути ... очевидно, что определение ваш слова «статический» не соответствует определению «статический» командой компиляторов C#. Очевидно, что можно создать то, о чем вы просите (как указывает Липперт, и как другие указывали на разных языках), но мы не будем называть их «статическими» методами, если команда компилятора C# не изменит их определение. .

Mark Brackett 19.03.2015 20:17

Очевидный вариант использования - это отделение от конкретного класса для поддержки DI и тестирования «статической» реализации. Я думаю, что случай с «типовым методом», о котором вы говорите, удовлетворит эту потребность, если бы он был реализован на C#. Я полагаю, что в большинстве случаев разработчики не так озабочены внутренней работой vtable или детерминированным разрешением метода (и в большинстве случаев это не должно быть), но имеют потребность более высокого порядка - или, по крайней мере, воображают, что они это делают. В любом случае, ваш +1 от меня, по большей части, за введение термина «компилятор-неуклюжий».

Richard Hauer 07.08.2016 08:33

@MarkBrackett "статический" определяется спецификацией C#. Добавление статических методов к интерфейсам не приведет к конфликту со спецификацией.

Mashmagar 14.02.2019 16:22

@Mashmagar - ну, если бы вы изменили спецификацию, это не противоречило бы .... но это в значительной степени тавтология и перекликается с тем, что я уже сказал. Такая вещь, очевидно, называется возможный и может называться как угодно ответственным за именование вещей. Однако на данный момент ответственные за добавление вещей не считают это ни в рамках определения «статического», ни достаточно полезной функцией для добавления под другим именем. Как правило, это всегда будет (возможно, не очень удовлетворительным) ответом на те вещи, которые возможны, но еще не реализованы ...

Mark Brackett 19.02.2019 17:51

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

Как бы вы это назвали ??


public interface MyInterface { void MyMethod(); }
public class MyClass: MyInterface
{
    public static void MyMethod() { //Do Something; }
}

 // inside of some other class ...  
 // How would you call the method on the interface ???
    MyClass.MyMethod();  // this calls the method normally 
                         // not through the interface...

    // This next fails you can't cast a classname to a different type... 
    // Only instances can be Cast to a different type...
    MyInterface myItf = MyClass as MyInterface;  

Другие языки (например, Java) позволяют вызывать статические методы из экземпляров объектов, хотя вы получите предупреждение о том, что их следует вызывать из статического контекста.

Chris Marasti-Georg 03.11.2008 21:48

Разрешение вызова статического метода из экземпляра также разрешено в .Net. Это другое дело. Если статический метод реализует интерфейс, вы можете вызвать его БЕЗ экземпляра. ЭТО то, что не имеет смысла. Помните, что вы не можете поместить реализацию в интерфейс, она должна быть в классе. Итак, если бы для реализации этого интерфейса были определены пять разных классов, каждый из которых имел бы свою реализацию этого статического метода, что бы использовал компилятор?

Charles Bretana 30.12.2014 17:48

@CharlesBretana в случае дженериков - тот, который соответствует переданному типу. Я вижу большую пользу в наличии интерфейсов для статических методов (или, если хотите, назовем их «статическими интерфейсами» и позволим классу определять оба статических интерфейса и интерфейсы экземпляров). Итак, если у меня есть Whatever<T>() where T:IMyStaticInterface, я мог бы вызвать Whatever<MyClass>() и иметь T.MyStaticMethod() внутри реализации Whatever<T>() без необходимости в экземпляре. Метод для вызова будет определен во время выполнения. Вы можете сделать это через рефлексию, но здесь нет «контракта», который можно было бы принудить.

Jcl 03.03.2015 17:42

Приведу пример, в котором мне не хватает либо статической реализации методов интерфейса, либо того, что Марк Брэкетт представил как «так называемый метод типа»:

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

interface IDataRow {
  string GetDataSTructre();  // How to read data from the DB
  void Read(IDBDataRow);     // How to populate this datarow from DB data
}

public class DataTable<T> : List<T> where T : IDataRow {

  public string GetDataStructure()
    // Desired: Static or Type method:
    // return (T.GetDataStructure());
    // Required: Instantiate a new class:
    return (new T().GetDataStructure());
  }

}

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

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

У меня было несколько классов статического бизнес-уровня, в которых реализованы методы CRUD, такие как «Create», «Read», «Update», «Delete» для каждого типа сущности, такого как «User», «Team» и т. д. Затем я создал базу элемент управления, имеющий абстрактное свойство для класса бизнес-уровня, реализующего методы CRUD. Это позволило мне автоматизировать операции «Создать», «Прочитать», «Обновить», «Удалить» из базового класса. Мне пришлось использовать Singleton из-за статического ограничения.

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

Предположим, у нас есть параметр типа в универсальном методе, и нам нужно проделать с ним некоторую операцию. Мы не хотим мгновенно создавать, потому что не знаем конструкторов.

Например:

Repository GetRepository<T>()
{
  //need to call T.IsQueryable, but can't!!!
  //need to call T.RowCount
  //need to call T.DoSomeStaticMath(int param)
}

...
var r = GetRepository<Customer>()

К сожалению, я могу придумать только «уродливые» альтернативы:

  • Используйте отражение Некрасиво и бьет идея интерфейсов и полиморфизма.

  • Создать полностью отдельный фабричный класс

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

  • Создайте экземпляр, а затем вызовите нужный метод интерфейса

    Это может быть сложно реализовать, даже если мы контролируем источник для классов, используемый в качестве общих параметров. Причина в том, что, например, нам может потребоваться, чтобы экземпляры были только в хорошо известном состоянии «подключены к БД».

Пример:

public class Customer 
{
  //create new customer
  public Customer(Transaction t) { ... }

  //open existing customer
  public Customer(Transaction t, int id) { ... }

  void SomeOtherMethod() 
  { 
    //do work...
  }
}

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

public class Customer: IDoSomeStaticMath
{
  //create new customer
  public Customer(Transaction t) { ... }

  //open existing customer
  public Customer(Transaction t, int id) { ... }

  //dummy instance
  public Customer() { IsDummy = true; }

  int DoSomeStaticMath(int a) { }

  void SomeOtherMethod() 
  { 
    if (!IsDummy) 
    {
      //do work...
    }
  }
}

Это явно некрасиво, а также излишне усложняет код для всех других методов. Очевидно, это тоже не изящное решение!

+1 за «Большинство ответов здесь, кажется, упускают из виду суть»; невероятно, как кажется, что почти все ответы уклоняются от сути вопроса, чтобы углубиться в в основном бесполезное словоблудие ...

user610650 31.05.2012 20:06

Ваши примеры не имеют для меня смысла ... функциональность "IsQueryable" может быть аннотацией / атрибутом или, еще лучше, интерфейсом, который реализует класс (иначе, как вы его запрашиваете?). RowCount ... чего? Количество клиентов? Это то, что должен делать репозиторий клиентов, а не класс клиентов. Пример статической математики неполный, поэтому я не уверен, что вы на самом деле пытаетесь там сделать.

Chris Marasti-Georg 23.10.2012 18:54

@Chris Вот конкретный пример, который заставил меня снова столкнуться с этим ограничением. Я хочу добавить интерфейс IResettable к классам, чтобы указать, что они кэшируют определенные данные в статических переменных, которые могут быть сброшены администратором сайта (например, список категорий заказа, набор ставок НДС, список категорий, полученных из внешнего API) чтобы уменьшить количество обращений к БД и внешнему API, очевидно, что потребуется сброс статического метода. Это позволяет мне просто автоматизировать определение классов, которые можно сбросить. Я все еще могу это сделать, но этот метод не применяется и не добавляется автоматически в IDE и полагается на надежду.

mattmanser 26.10.2012 18:18

@mattmanser Я бы сказал, что вы достигли точки в своей архитектуре, когда вам нужно использовать фактический кеш, а не статические переменные в объектах домена (решение, которое я бы тоже поставил под сомнение, но это другое обсуждение :)).

Chris Marasti-Georg 26.10.2012 23:00

@Chris Я не согласен, массовое убийство. Когда больше архитектуры - «лучшее» решение, это всегда признак языковой ошибки. Помните все шаблоны, о которых больше никто не говорит с тех пор, как в C# появились универсальные шаблоны и анонимные методы?

mattmanser 30.10.2012 13:15

Разве вы не можете использовать «where T: IQueryable, T: IDoSomeStaticMath» или подобное?

Roger Willcocks 07.12.2012 06:44

@ ChrisMarasti-Georg: Классический пример - это типизированные классы баз данных, все из которых имеют функцию извлечения по ключу. Customer cust = Customer.Retrieve(233);. Эти классы базы данных часто наследуют один тип «класса базы данных» и часто имеют общие свойства, но вы никогда не сможете определить / вызвать их функцию (ы) Retrieve как общую вещь, потому что она статична, несмотря на то, что она у всех есть.

Nyerguds 06.05.2015 13:03

@Nyerguds Верно, это было бы неплохим вариантом использования. Вы могли бы иметь что-то вроде T Retrieve<T: BaseDbClass>(long id) на вашем BaseDbClass, что, я думаю, все еще довольно интуитивно понятно.

Chris Marasti-Georg 06.05.2015 16:47

@ ChrisMarasti-Georg: Несколько грязный, но интересный способ обойти это небольшая конструкция: public abstract class DBObject<T> where T : DBObject<T>, new(), а затем сделать наследование всех классов DB как DBObject<T>. Затем вы можете сделать извлечение по ключу статической функцией с возвращаемым типом T в абстрактном суперклассе, заставить эту функцию создать новый объект T, а затем вызвать защищенный String GetRetrieveByKeyQuery() (определенный как абстрактный в суперклассе) для этого объекта, чтобы получить фактический запрос для выполнения. Хотя это может быть немного не по теме

Nyerguds 12.05.2015 16:26

@Nyerguds, это может сработать, но это ужасный взлом create an instance using reflection (new() constraint does) and fill with method. Create an instance не равен create an empty dummy instance and then fill it

Alex Zhukovskiy 29.12.2015 17:41

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

Nyerguds 12.01.2016 16:09

@Nyerguds Я думаю, должна быть какая-то возможность разрешить интерфейсам иметь статические методы, поэтому тип, который наследует этот интерфейс, должен иметь специальный статический метод. Это может быть полезно для любых методов, таких как T Parse(string source);

Alex Zhukovskiy 13.01.2016 13:20

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

Nyerguds 13.01.2016 15:55

@Nyerguds, теперь это правда, но именно поэтому я так говорю. Если бы эта функция была включена в спецификации CIL при ее разработке, это было бы намного проще. Компилятору просто нужно, чтобы у определенного класса был какой-то метод. Мы всегда можем создать экземпляр объекта и вызвать метод интерфейса Parse, но это не то же самое, что создать его из статического метода, потому что класс может иметь поля только для чтения, которые могут быть инициализированы только во время создания.

Alex Zhukovskiy 14.01.2016 13:26

Я знаю, что это старый вопрос, но он интересный. Пример не лучший. Думаю, было бы намного понятнее, если бы вы показали пример использования:

string DoSomething<T>() where T:ISomeFunction
{
  if (T.someFunction())
    ...
}

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

  1. Создайте статический универсальный класс, параметром типа которого будет тип, который вы передадите в DoSomething выше. Каждый вариант этого класса будет иметь один или несколько статических членов, содержащих материалы, относящиеся к этому типу. Эта информация может быть предоставлена ​​либо путем вызова каждым интересующим классом подпрограммы «информации о регистре», либо путем использования Reflection для получения информации при запуске статического конструктора варианта класса. Я считаю, что последний подход используется такими вещами, как Comparer <T> .Default ().
  2. Для каждого интересующего класса T определите класс или структуру, которая реализует IGetWhateverClassInfo <T> и удовлетворяет «новому» ограничению. Класс фактически не будет содержать никаких полей, но будет иметь статическое свойство, которое возвращает статическое поле с информацией о типе. Передайте тип этого класса или структуры рассматриваемой универсальной подпрограмме, которая сможет создать экземпляр и использовать его для получения информации о другом классе. Если вы используете класс для этой цели, вам, вероятно, следует определить статический универсальный класс, как указано выше, чтобы не создавать каждый раз новый экземпляр объекта-дескриптора. Если вы используете структуру, стоимость создания экземпляра должна быть равна нулю, но для каждого другого типа структуры потребуется другое расширение подпрограммы DoSomething.

Ни один из этих подходов не выглядит привлекательным. С другой стороны, я ожидал бы, что если бы в CLR существовали механизмы для чистого обеспечения такого рода функциональности, .net позволил бы указать параметризованные «новые» ограничения (поскольку знание того, имеет ли класс конструктор с определенной сигнатурой, казалось бы быть сопоставимым по сложности со знанием того, есть ли у него статический метод с определенной сигнатурой).

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

Все вышеперечисленные аргументы, похоже, упускают из виду этот пункт о контрактах.

Я полностью согласен с этим простым, но эффективным ответом. Что было бы интересно в «статическом интерфейсе», так это то, что он представлял бы контракт. Возможно, это не следует называть «статическим интерфейсом», но мы все равно пропускаем конструкцию. Например, проверьте официальный документ .NET об интерфейсе ICustomMarshaler. Он требует, чтобы класс, реализующий его, «добавил статический метод с именем GetInstance, который принимает String в качестве параметра и имеет тип возврата ICustomMarshaler». Это действительно похоже на определение "статического интерфейса" на простом английском языке, в то время как я бы предпочел его на C# ...

Simon Mourier 27.10.2015 12:48

@SimonMourier Эту документацию можно было бы написать более четко, но вы неправильно ее истолковываете. Статический метод GetInstance требуется не для интерфейса ICustomMarshaler. Этого требует атрибут кода [MarshalAs]. Они используют фабричный шаблон, чтобы атрибут мог получить экземпляр присоединенного упаковщика. К сожалению, они полностью забыли включить документирование требования GetInstance на страницу документации MarshalAs (на ней показаны только примеры с использованием встроенных реализаций маршалинга).

Scott Gartner 20.06.2017 22:53

@ScottGartner - Не понимаю. В msdn.microsoft.com/en-us/library/… четко сказано: «Помимо реализации интерфейса ICustomMarshaler, пользовательские упаковщики должны реализовывать статический метод GetInstance, который принимает String в качестве параметра и имеет тип возвращаемого значения ICustomMarshaler. Этот статический метод вызывается уровнем взаимодействия COM среды CLR. для создания экземпляра настраиваемого упаковщика. ". Это определенно статическое определение контракта.

Simon Mourier 20.06.2017 23:53

Большинство людей, кажется, забывают, что в ООП классы тоже являются объектами, и поэтому у них есть сообщения, которые по какой-то причине C# вызывает «статический метод». Тот факт, что существуют различия между объектами экземпляра и объектами класса, только указывает на недостатки языка. Хотя оптимист по поводу C# ...

Проблема в том, что этот вопрос не о "в ООП". Это про "на C#". В C# нет «сообщений».

John Saunders 14.12.2013 23:09

Хорошо, вот пример необходимости «метода типа». Я создаю один из набора классов на основе некоторого исходного XML. Так что у меня есть

  static public bool IsHandled(XElement xml)

функция, которая вызывается по очереди для каждого класса.

Функция должна быть статической, иначе мы тратим время на создание неподходящих объектов. Как отмечает @Ian Boyde, это можно сделать в фабричном классе, но это только добавляет сложности.

Было бы неплохо добавить его в интерфейс, чтобы заставить разработчиков классов реализовать его. Это не вызовет значительных накладных расходов - это всего лишь проверка времени компиляции / компоновки и не влияет на vtable.

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

Так что это второстепенная потенциальная функция, которую в конечном итоге, вероятно, лучше не учитывать.

Что касается статических методов, используемых в неуниверсальных контекстах, я согласен с тем, что не имеет большого смысла разрешать их в интерфейсах, так как вы не смогли бы их вызвать, если бы у вас была ссылка на интерфейс в любом случае. Однако в дизайне языка есть фундаментальная дыра, созданная за счет использования интерфейсов НЕ в полиморфном контексте, а в общем. В этом случае интерфейс вовсе не интерфейс, а скорее ограничение. Поскольку в C# нет концепции ограничений вне интерфейса, в нем отсутствуют существенные функциональные возможности. Дело в точке:

T SumElements<T>(T initVal, T[] values)
{
    foreach (var v in values)
    {
        initVal += v;
    }
}

Здесь нет полиморфизма, универсальный использует фактический тип объекта и вызывает оператор + =, но это не удается, поскольку он не может точно сказать, что этот оператор существует. Простое решение - указать это в ограничении; простое решение невозможно, потому что операторы являются статическими, а статические методы не могут быть в интерфейсе и (вот в чем проблема) ограничения представлены как интерфейсы.

Что нужно C#, так это реальный тип ограничения, все интерфейсы также будут ограничениями, но не все ограничения будут интерфейсами, тогда вы можете сделать это:

constraint CHasPlusEquals
{
    static CHasPlusEquals operator + (CHasPlusEquals a, CHasPlusEquals b);
}

T SumElements<T>(T initVal, T[] values) where T : CHasPlusEquals
{
    foreach (var v in values)
    {
        initVal += v;
    }
}

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

Операторы в C# статичны, поэтому в этом нет смысла.

John Saunders 13.08.2013 22:39

В этом суть, ограничение проверяет, что ТИП (не экземпляр) имеет оператор + (и, как расширение, оператор + =) и позволяет сгенерировать шаблон, а затем, когда происходит фактическая подстановка шаблона, используемый объект гарантированно будет типа, который имеет этот оператор (или другой статический метод). Итак, вы можете сказать: SumElements <int> (0, 5); который будет создавать это: SumElements (int initVal, int [] values) {foreach (var v in values) {initVal + = v; }}, что, конечно, имеет смысл

Jeremy Sorensen 14.08.2013 01:44

Помните, что это не шаблон. Это универсальные шаблоны, которые отличаются от шаблонов C++.

John Saunders 14.08.2013 01:46

@JohnSaunders: универсальные шаблоны не являются шаблонами, и я не знаю, как их можно разумно заставить работать со статически привязанными операторами, но в общих контекстах есть много случаев, когда было бы полезно указать, что T должен иметь Член статический (например, фабрика, производящая экземпляры T). Я думаю, что даже без изменений во время выполнения можно было бы определить соглашения и вспомогательные методы, которые позволили бы языкам реализовать такую ​​вещь, как синтаксический сахар, эффективным и совместимым образом. Если бы для каждого интерфейса с виртуальными статическими методами был вспомогательный класс ...

supercat 14.12.2013 22:51

... тогда, если T ограничен IFoo<T>, T.CreateThing(paramString) станет IFoo_Helper<T>.CreateThing(paramString), а в классе Fred, который реализует IFoo<Fred>, определение static Fred IFoo.CreateThing(string st) пометит метод так, чтобы метод IFoo_Helper мог найти его через Reflection в первый раз, когда это понадобится [будущее доступ будет через кэшированного делегата].

supercat 14.12.2013 22:57

@supercat: Мне кажется, я действительно видел несколько подобных примеров. Единственное, что мешает тому или иному методу быть static, - это то, что он реализует член интерфейса.

John Saunders 14.12.2013 23:11

@JohnSaunders: Проблема не столько в том, что метод реализует интерфейс, сколько в том, что компилятор не может выбрать виртуальный метод для вызова, не имея экземпляра объекта, на котором основывается выбор. Решение состоит в том, чтобы отправлять вызов «статического интерфейса» без использования виртуальной диспетчеризации (которая не будет работать), а вместо этого использовать вызов общего статического класса. Универсальная диспетчеризация на основе типов не требует наличия экземпляра, а просто наличия типа.

supercat 15.12.2013 00:53

Я думаю, что вопрос заключается в том, что C# нужно другое ключевое слово именно для таких ситуаций. Вам нужен метод, возвращаемое значение которого зависит только от типа, для которого он вызывается. Вы не можете назвать это "статическим", если указанный тип неизвестен. Но как только тип станет известен, он станет статичным. Идея заключается в «неразрешенной статике» - она ​​еще не статична, но, как только мы узнаем тип получения, она станет. Это совершенно хорошая концепция, поэтому программисты постоянно ее просят. Но это не совсем соответствовало тому, как дизайнеры думали о языке.

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

public interface IZeroWrapper<TNumber> {
  TNumber Zero {get;}
}

public class DoubleWrapper: IZeroWrapper<double> {
  public double Zero { get { return 0; } }
}

Тот факт, что статический класс реализован на C# путем создания Microsoft специального экземпляра класса со статическими элементами, является лишь странностью того, как достигается статическая функциональность. Это не теоретический момент.

Интерфейс ДОЛЖЕН быть дескриптором интерфейса класса - или того, как он взаимодействует, и это должно включать статические взаимодействия. Общее определение интерфейса (от Meriam-Webster): место или область, в которой разные вещи встречаются и взаимодействуют друг с другом или влияют друг на друга. Когда вы полностью опускаете статические компоненты класса или статические классы, мы игнорируем большие части того, как эти плохие парни взаимодействуют.

Вот очень наглядный пример того, где было бы весьма полезно использовать интерфейсы со статическими классами:

public interface ICrudModel<T, Tk>
{
    Boolean Create(T obj);
    T Retrieve(Tk key);
    Boolean Update(T obj);
    Boolean Delete(T obj);
}

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

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

Nathan Tuggy 26.07.2015 03:47

C# и CLR должны поддерживать статические методы в интерфейсах, как это делает Java. Модификатор static является частью определения контракта и имеет значение, в частности, поведение и возвращаемое значение не меняются в зависимости от экземпляра, хотя они могут по-прежнему меняться от вызова к вызову.

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

As per Object oriented concept Interface implemented by classes and have contract to access these implemented function(or methods) using object.

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

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

Концептуально нет причин, по которым интерфейс не может определить контракт, который включает статические методы.

Для текущей реализации языка C# ограничение связано с разрешением наследования базового класса и интерфейсов. Если «класс SomeBaseClass» реализует «интерфейс ISomeInterface», а «класс SomeDerivedClass: SomeBaseClass, ISomeInterface» также реализует интерфейс, статический метод для реализации метода интерфейса не сможет скомпилировать, поскольку статический метод не может иметь такую ​​же сигнатуру, что и метод экземпляра (что могло бы присутствовать в базовом классе для реализации интерфейса).

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

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

Другие вопросы по теме