Почему 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;
}
....
}
c#
oop
language-features
Kramii
источник
источник
IListItem.ScreenName() => ScreenName()
(используя синтаксис C # 7) реализует интерфейсный метод явно, вызывая статический метод. Тем не менее, все становится ужасно, когда вы добавляете наследование к этому (вы должны переопределить интерфейс)Ответы:
Предположим, вы спрашиваете, почему вы не можете сделать это:
Это не имеет смысла для меня, семантически. Методы, указанные в интерфейсе, должны быть там, чтобы указать контракт для взаимодействия с объектом. Статические методы не позволяют вам взаимодействовать с объектом - если вы оказались в положении, в котором ваша реализация может стать статичной, вам, возможно, придется спросить себя, действительно ли этот метод принадлежит интерфейсу.
Чтобы реализовать ваш пример, я бы дал Animal свойство const, которое все равно позволяло бы к нему доступ из статического контекста, и возвращал бы это значение в реализации.
Для более сложной ситуации вы всегда можете объявить другой статический метод и делегировать его. Пытаясь придумать пример, я не мог придумать ни одной причины, по которой вы бы сделали что-то нетривиальное как в статическом, так и в контексте экземпляра, поэтому я избавлю вас от двоичного объекта FooBar и приму его в качестве указания на то, что он может не будет хорошей идеей
источник
public static object MethodName(this IBaseClass base)
внутри статического класса. Недостатком, однако, является то, что в отличие от наследования интерфейса - это не заставляет / позволяет отдельным наследникам хорошо переопределять методологию.Моя (упрощенная) техническая причина заключается в том, что статические методы отсутствуют в vtable , а сайт вызовов выбирается во время компиляции. Это та же самая причина, по которой у вас не может быть переопределения или виртуальных статических членов. Для получения более подробной информации вам понадобится выпускник CS или компилятор - а я ни один из них.
По политическим причинам я процитирую Эрика Липперта (который является победителем компилятора и имеет степень бакалавра математики, информатики и прикладной математики из Университета Ватерлоо (источник: LinkedIn ):
Обратите внимание, что Липперт оставляет место для так называемого метода типа:
но еще предстоит убедиться в его полезности.
источник
object
s и как им разрешено реализовывать интерфейсы.Func<>
делает, но вместо того, чтобы содержать только один указатель, он содержит все указатели для методов, требуемых интерфейсом. Использованиеstatic
like в статической диспетчеризации делает искусственно затрудняющий язык ради «объектно-ориентированной».Большинство ответов здесь, кажется, пропускают всю суть. Полиморфизм можно использовать не только между экземплярами, но и между типами. Это часто необходимо, когда мы используем дженерики.
Предположим, у нас есть параметр типа в универсальном методе, и нам нужно выполнить с ним некоторую операцию. Мы не хотим мгновенно, потому что мы не знаем конструкторов.
Например:
К сожалению, я могу придумать только «некрасивые» альтернативы:
Используйте рефлексию Гадкий и бьет идею интерфейсов и полиморфизма.
Создать полностью отдельный заводской класс
Это может значительно увеличить сложность кода. Например, если мы пытаемся смоделировать доменные объекты, каждому объекту потребуется другой класс репозитория.
Создайте экземпляр и затем вызовите нужный метод интерфейса
Это может быть трудно реализовать, даже если мы контролируем источник для классов, используемых в качестве общих параметров. Причина в том, что, например, нам может потребоваться, чтобы экземпляры были только в хорошо известном состоянии «подключен к БД».
Пример:
чтобы использовать мгновенное решение для решения проблемы статического интерфейса, нам нужно сделать следующее:
Это явно уродливо, а также ненужно усложняет код для всех других методов. Очевидно, тоже не элегантное решение!
источник
public abstract class DBObject<T> where T : DBObject<T>, new()
а затем заставить все классы DB наследовать какDBObject<T>
. Затем вы можете сделать извлечение по ключу статической функцией с типом возврата T в абстрактном суперклассе, заставить эту функцию создать новый объект T, а затем вызвать защищенныйString GetRetrieveByKeyQuery()
(определенный как абстрактный в суперклассе) этот объект для получения фактический запрос для выполнения. Хотя это может быть немного не по темеЯ знаю, что это старый вопрос, но это интересно. Пример не самый лучший. Я думаю, было бы намного понятнее, если бы вы показали пример использования:
Простая способность иметь статические методы для реализации интерфейса не даст желаемого; то, что было бы необходимо, было бы иметь статические члены как часть интерфейса. Я, конечно, могу представить множество вариантов использования для этого, особенно когда речь идет о возможности создавать вещи. Я мог бы предложить два подхода, которые могут быть полезны:
Ни один из этих подходов не является действительно привлекательным. С другой стороны, я ожидал бы, что если бы в CLR существовали механизмы, обеспечивающие чистую функциональность такого рода, .net позволил бы задавать параметризованные «новые» ограничения (поскольку знание того, имеет ли класс конструктор с определенной сигнатурой, может показаться быть сравнимым по сложности с тем, чтобы знать, имеет ли он статический метод с определенной сигнатурой).
источник
Я думаю, близорукость.
Первоначально разработанные интерфейсы предназначались только для использования с экземплярами класса.
Только с введением интерфейсов, поскольку ограничения для обобщений сделали практическое использование добавления статического метода в интерфейс.
(отвечает на комментарий :) Я полагаю, что изменение этого сейчас потребует изменения CLR, что приведет к несовместимости с существующими сборками.
источник
Интерфейсы определяют поведение объекта.
Статические методы определяют не поведение объекта, а поведение, которое каким-то образом влияет на объект.
источник
В той степени, в которой интерфейсы представляют «контракты», для статических классов представляется разумным реализовать интерфейсы.
Все вышеперечисленные аргументы, похоже, упускают этот момент в отношении контрактов.
источник
Поскольку цель интерфейса - разрешить полиморфизм, возможность передавать экземпляр любого числа определенных классов, которые все были определены для реализации определенного интерфейса ... гарантируя, что в вашем полиморфном вызове код сможет найти метод, который вы вызываете. нет смысла разрешать статический метод для реализации интерфейса,
Как бы вы назвали это ??
источник
Whatever<T>() where T:IMyStaticInterface
я мог бы позвонитьWhatever<MyClass>()
и иметьT.MyStaticMethod()
внутриWhatever<T>()
реализации без необходимости экземпляра. Метод для вызова будет определен во время выполнения. Вы можете сделать это с помощью рефлексии, но нет никакого «контракта», который нужно навязывать.Что касается статических методов, используемых в неуниверсальных контекстах, я согласен, что не имеет смысла разрешать их в интерфейсах, так как вы не сможете вызывать их, если у вас все равно есть ссылка на интерфейс. Однако есть фундаментальная дыра в дизайне языка, созданная с использованием интерфейсов НЕ в полиморфном контексте, а в общем. В этом случае интерфейс - это вовсе не интерфейс, а скорее ограничение. Поскольку C # не имеет понятия ограничения вне интерфейса, ему не хватает существенной функциональности. Дело в точке:
Здесь нет полиморфизма, универсальный использует фактический тип объекта и вызывает оператор + =, но это не удается, поскольку он не может точно сказать, что этот оператор существует. Простое решение - указать его в ограничении; простое решение невозможно, потому что операторы являются статическими, а статические методы не могут быть в интерфейсе, и (здесь проблема) ограничения представлены в виде интерфейсов.
То, что нужно C #, - это реальный тип ограничений, все интерфейсы также будут ограничениями, но не все ограничения будут интерфейсами, тогда вы могли бы сделать это:
Уже было много разговоров о создании IArithmetic для всех реализуемых числовых типов, но существует обеспокоенность по поводу эффективности, так как ограничение не является полиморфной конструкцией, а ограничение CArithmetic решит эту проблему.
источник
T
должно иметь статическое член (например, фабрика, которая производитT
экземпляры). Даже без изменений во время выполнения, я думаю, что было бы возможно определить соглашения и вспомогательные методы, которые позволили бы языкам реализовать такую вещь как синтаксический сахар эффективным и совместимым образом. Если бы для каждого интерфейса с виртуальными статическими методами существовал вспомогательный класс ...Потому что интерфейсы находятся в структуре наследования, а статические методы не наследуются хорошо.
источник
То, что вы, похоже, хотите, позволило бы вызывать статический метод как через тип, так и через любой экземпляр этого типа. Это, по крайней мере, приведет к двусмысленности, которая не является желательной чертой.
Были бы бесконечные дебаты о том, имеет ли это значение, что является лучшей практикой, и есть ли проблемы с производительностью, делающие это так или иначе. Просто не поддерживая его, C # избавляет нас от необходимости беспокоиться об этом.
Также вероятно, что компилятор, соответствующий этому желанию, потеряет некоторые оптимизации, которые могут сопровождаться более строгим разделением между экземпляром и статическими методами.
источник
Вы можете думать о статических методах и нестатических методах класса как о различных интерфейсах. При вызове статические методы разрешаются в одноэлементном статическом объекте класса, а нестатические методы разрешаются в экземпляре класса, с которым вы работаете. Итак, если вы используете статические и нестатические методы в интерфейсе, вы бы фактически объявили два интерфейса, когда мы действительно хотим, чтобы интерфейсы использовались для доступа к одной связной вещи.
источник
В качестве примера, где мне не хватает статической реализации методов интерфейса или того, что Марк Брэкетт представил как «метод так называемого типа»:
При чтении из хранилища базы данных у нас есть универсальный класс DataTable, который обрабатывает чтение из таблицы любой структуры. Вся специфичная для таблицы информация помещается в один класс для каждой таблицы, которая также содержит данные для одной строки из БД и должна реализовывать интерфейс IDataRow. В IDataRow включено описание структуры таблицы для чтения из базы данных. DataTable должен запросить структуру данных из IDataRow перед чтением из БД. В настоящее время это выглядит так:
GetDataStructure требуется только один раз для каждой таблицы для чтения, накладные расходы на создание еще одного экземпляра минимальны. Впрочем, было бы неплохо в этом случае здесь.
источник
К вашему сведению: вы можете получить поведение, похожее на то, что вы хотите, создав методы расширения для интерфейса. Метод расширения будет общим, не переопределяемым статическим поведением. Однако, к сожалению, этот статический метод не будет частью контракта.
источник
Интерфейсы - это абстрактные наборы определенных доступных функций.
Независимо от того, ведет себя метод в этом интерфейсе как статический или нет, это деталь реализации, которая должна быть скрыта за интерфейсом. . Было бы неправильно определять интерфейсный метод как статический, потому что вы бы излишне заставляли метод быть реализованным определенным образом.
Если бы методы были определены как статические, класс, реализующий интерфейс, не был бы настолько инкапсулирован, как мог бы. Инкапсуляция - это хорошая вещь, к которой нужно стремиться в объектно-ориентированном дизайне (я не буду вдаваться в причину, вы можете прочитать это здесь: http://en.wikipedia.org/wiki/Object-oriented ). По этой причине статические методы не допускаются в интерфейсах.
источник
Статические классы должны быть в состоянии сделать это, чтобы их можно было использовать в общем. Мне пришлось вместо этого реализовать Singleton для достижения желаемых результатов.
У меня было несколько классов Static Business Layer, в которых реализованы такие методы CRUD, как «Создать», «Чтение», «Обновление», «Удалить» для каждого типа сущностей, таких как «Пользователь», «Команда» и т. Д. Затем я создал базу элемент управления с абстрактным свойством для класса бизнес-уровня, в котором реализованы методы CRUD. Это позволило мне автоматизировать операции «Создать», «Чтение», «Обновить», «Удалить» из базового класса. Мне пришлось использовать Синглтон из-за статического ограничения.
источник
Кажется, большинство людей забывают, что в ООП классы тоже являются объектами, и поэтому у них есть сообщения, которые по какой-то причине c # называет «статическим методом». Тот факт, что существуют различия между объектами экземпляра и объектами класса, показывает только недостатки или недостатки в языке. Оптимист о c # хотя ...
источник
Хорошо, вот пример необходимости «метода типа». Я создаю один из набора классов на основе исходного XML. Итак, у меня есть
функция, которая вызывается по очереди на каждый класс.
Функция должна быть статической, так как в противном случае мы тратим время на создание неподходящих объектов. Как отмечает @Ian Boyde, это можно сделать на фабричном классе, но это только добавляет сложности.
Было бы неплохо добавить его в интерфейс, чтобы заставить разработчиков классов реализовать его. Это не приведет к значительным накладным расходам - это только проверка времени компиляции / компоновки и не влияет на vtable.
Тем не менее, это также будет довольно незначительным улучшением. Поскольку метод является статическим, я, как вызывающая программа, должен вызывать его явно и, таким образом, получить немедленную ошибку компиляции, если он не реализован. Разрешение указывать его на интерфейсе будет означать, что эта ошибка появляется незначительно раньше в цикле разработки, но это тривиально по сравнению с другими проблемами с неработающим интерфейсом.
Так что это небольшая потенциальная особенность, которую лучше всего не учитывать.
источник
Тот факт, что статический класс реализован в C # корпорацией Microsoft, создавая специальный экземпляр класса со статическими элементами, является лишь странностью того, как достигается статическая функциональность. Это не теоретический момент.
Интерфейс ДОЛЖЕН быть дескриптором интерфейса класса - или того, как с ним взаимодействуют, и это должно включать статические взаимодействия. Общее определение интерфейса (от Meriam-Webster): место или область, в которой разные вещи встречаются, общаются или влияют друг на друга. Когда вы полностью опускаете статические компоненты класса или статические классы, мы игнорируем большие разделы о том, как эти плохие парни взаимодействуют.
Вот очень четкий пример того, где возможность использовать интерфейсы со статическими классами была бы весьма полезна:
В настоящее время я пишу статические классы, которые содержат эти методы, без какой-либо проверки, чтобы убедиться, что я ничего не забыл. Это как плохие старые времена программирования до ООП.
источник
C # и CLR должны поддерживать статические методы в интерфейсах, как это делает Java. Модификатор static является частью определения контракта и имеет значение, в частности, то, что поведение и возвращаемое значение не меняются в зависимости от экземпляра, хотя оно все еще может варьироваться от вызова к вызову.
Тем не менее, я рекомендую, если вы хотите использовать статический метод в интерфейсе и не можете использовать аннотацию вместо этого. Вы получите функциональность, которую вы ищете.
источник
Я думаю, что короткий ответ «потому что он нулевой полезности». Чтобы вызвать метод интерфейса, вам нужен экземпляр типа. Из методов экземпляра вы можете вызывать любые статические методы, которые захотите.
источник
Я думаю, что вопрос заключается в том, что C # нуждается в другом ключевом слове, именно для такой ситуации. Вам нужен метод, возвращаемое значение которого зависит только от типа, для которого он вызывается. Вы не можете назвать это «статическим», если указанный тип неизвестен. Но как только тип станет известным, он станет статичным. «Неразрешенная статика» - это идея - она еще не статична, но как только мы узнаем тип приема, он будет. Это очень хорошая концепция, поэтому программисты постоянно просят об этом. Но это не совсем соответствовало тому, как дизайнеры думали о языке.
Поскольку он недоступен, я привык использовать нестатические методы, как показано ниже. Не совсем идеально, но я не вижу подходов, которые имеют больше смысла, по крайней мере, не для меня.
источник
Поэтому, если вы хотите получить доступ к методам Interface Contract, вам нужно создать объект. Это всегда должно быть запрещено в случае статических методов. Статические классы, метод и переменные никогда не требуют объектов и загружаются в память без создания объекта этой области (или класса), или вы можете сказать, что не требуют создания объектов.
источник
Концептуально нет причины, по которой интерфейс не мог бы определить контракт, включающий статические методы.
Для текущей реализации языка C # ограничение связано с разрешением наследования базового класса и интерфейсов. Если «класс SomeBaseClass» реализует «интерфейс ISomeInterface» и «класс SomeDerivedClass: SomeBaseClass, ISomeInterface» также реализует интерфейс, статический метод для реализации метода интерфейса может не скомпилироваться, поскольку статический метод не может иметь такую же сигнатуру, как метод экземпляра (что присутствовать в базовом классе для реализации интерфейса).
Статический класс функционально идентичен синглтону и служит той же цели, что и синглтон с более чистым синтаксисом. Поскольку синглтон может реализовывать интерфейс, реализации интерфейса с помощью статики концептуально допустимы.
Таким образом, это просто сводится к ограничению конфликта имен C #, например, и статических методов с одним и тем же именем в наследовании. Нет причин, по которым C # не может быть «обновлен» для поддержки контрактов статических методов (интерфейсов).
источник
Когда класс реализует интерфейс, он создает экземпляр для членов интерфейса. В то время как статический тип не имеет экземпляра, нет смысла иметь статические подписи в интерфейсе.
источник