C # static member “inheritance” – почему это вообще существует?

В C # статические члены суперclassа «наследуются» в область подclassов. Например:

class A { public static int M() { return 1; } } class B : A {} class C : A { public new static int M() { return 2; } } [...] AM(); //returns 1 BM(); //returns 1 - this is equivalent to AM() CM(); //returns 2 - this is not equivalent to AM() 

Теперь вы не можете наследовать статические classы, и единственное место, где я могу себе представить, что статическое наследование может иметь значение, игнорирует его полностью: хотя вы можете сделать общее ограничение, которое требует, чтобы параметр типа T был подclassом A , вы все равно не можете позвонить TM() (что, вероятно, упрощает работу для виртуальной машины), не говоря уже о написании другой реализации M в подclassе и ее использовании.

Таким образом, «наследование» статических членов просто выглядит как загрязнение пространства имен; даже если вы явно квалифицируете имя (то есть BM ) A Версия A все еще разрешена.

Изменить сравнение с пространствами имен:

 namespace N1{ class X(); } namespace N1.N2 { class X(); } namespace N1.N2.N3 { [...] } 

В N1.N2.N3 Имеет смысл, что если я использую X без квалификации, это относится к N1.N2.X Но если я явно ссылаюсь на N1.N2.N3.X – и такой class не существует, я не ожидаю, что он найдет версию N2 ; и, действительно, компилятор сообщает об ошибке, если вы попробуете это. В отличие от этого, если я явно ссылаюсь на BM() , почему компилятор не сообщает об ошибке? В конце концов, нет метода «М» в «В» …

Какая цель имеет это наследование? Можно ли конструктивно использовать эту функцию?

Таким образом, «наследование» статических членов просто выглядит как загрязнение пространства имен

Правильно, за исключением того, что загрязнение одного парня связано с добавлением пряного аромата другого парня.

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

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

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

 public class Thing { // typical per-instance stuff int _member1; protected virtual void Foo() { ... } public void Bar() { ... } // factory method public static Thing Make() { return new Thing(); } } 

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

 public class AnotherThing : Thing { } 

Теперь у него есть статический метод Make который возвращает Thing , а не AnotherThing .

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

Но это всего лишь одна из тех слишком поздних вещей. У всех реальных рабочих языков (и библиотек и продуктов) есть несколько из них. C # очень мало.

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

При использовании Intellisense вы можете автоматически знать каждый статический член, ansible для этого classа.

Конечно, они не унаследованы, это просто ярлык

Вот как это работает , вероятно, просто глупый ответ в большинстве случаев. Но в этом случае так оно и работает; так как вы проистекаете из A, вы говорите, что являетесь A + дополнительными функциями, которые вы добавляете.

Поэтому вам нужно иметь доступ к тем же переменным, что и через экземпляр A.

Однако наследование статического classа не имеет никакого смысла, в то время как доступ к статическим членам / полям / методам.

Примером этого является следующее:

 internal class BaseUser { public static string DefaultUserPool { get; set; } } internal class User : BaseUser { public int Id { get; set; } public string Name { get; set; } public User Parent { get; set; } } 

Где тест выглядит следующим образом:

 User.DefaultUserPool = "Test"; BaseUser.DefaultUserPool = "Second Test"; Console.WriteLine(User.DefaultUserPool); Console.WriteLine(BaseUser.DefaultUserPool); 

Оба элемента WriteLines выводят «Второй тест», это связано с тем, что и BaseUser, и User должны использовать DefaultUserPool, по дизайну . И переопределение статических реализованных методов не создавало бы смысла mucn, поскольку это просто аксессор в дочернем classе.

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

На самом деле, как я понимаю, это просто ярлык, предоставленный компилятором. Синтаксис сахара. BM() будет просто компилироваться в AM() так как B не имеет static M() и A. Это проще для написания, ничего больше. Нет «статического наследования».

Добавлено: И требование для new когда «переопределение» просто так, что вы случайно не стреляете в ногу.

Я думаю, что это для доступа к защищенным статическим членам базового classа.

 class Base { protected static void Helper(string s) { Console.WriteLine(s); } } class Subclass : Base { public void Run() { Helper("From the subclass"); } } 

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

проигнорируйте вышеизложенное по какой-то причине, я думал о запечатанном вместо статического

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

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

Итак … Какая альтернатива?

В этом вопросе упоминается …

почему компилятор не сообщает об ошибке? В конце концов, нет метода «М» в «В» …

Но есть производный метод «М» в classе «В» .

Если компилятор не предоставил программисту единую виртуальную таблицу для базовых случаев, тогда программисту пришлось бы искать охоту через базовые типы, чтобы найти статические методы. Это нарушит polymorphism .

Википедия …

Политизм подтипов, почти универсально называемый просто polymorphismом в контексте объектно-ориентированного программирования, – это способность одного типа, A, появляться как и использоваться как другой тип, B ….

В сильно типизированных языках polymorphism обычно означает, что тип A каким-то образом происходит от типа B, или тип C реализует интерфейс, который представляет тип B.

  • Я не понимаю, зачем нам нужно «новое» ключевое слово
  • Почему ваш тип данных оператора switch не может быть длинным, Java?
  • Синтаксис для универсальных ссылок
  • Почему добавление null в строку законно?
  • Перегрузка функций по типу возврата?
  • Почему нельзя синхронизировать конструкторы Java?
  • Почему C ++ нужен отдельный заголовочный файл?
  • Давайте будем гением компьютера.