Другие указали, что это не переопределяет, но это все еще оставляет ваш первоначальный вопрос: почему вы в состоянии это сделать? (Но вопрос действительно «почему вы можете скрывать статические методы».)
Это неизбежная функция поддержки независимого управления версиями компонента, который содержит базовые классы и компоненты, которые используют эти базовые классы.
Например, представьте, что компонент CompB содержит базовый класс, а другой компонент CompD содержит производный класс. В версии 1 CompB, возможно, не было никакого свойства, называемого LogName. Автор CompD решает добавить статическое свойство LogName.
Ключевое значение для понимания на данном этапе заключается в том, что автор v1 CompD не собирался заменять или скрывать какую-либо функцию базового класса - в базовом классе не было ни одного элемента, называемого LogName, когда они написали этот код.
Теперь представьте, что выпущена новая версия библиотеки CompB. В этой новой версии автор добавил свойство LogName. Что должно произойти в CompD? Варианты кажутся:
- соед больше не работает, потому что он вводит LogName столкновения с LogName добавил к CompB
- Как-то сделать LogName в Соед по замене базы CompB LogName. (На самом деле это не совсем ясно, как это может работать со статикой. Однако вы можете предусмотреть это с нестатистикой.)
- Рассматривайте два члена LogName как совершенно разные члены, которые имеют одно и то же имя. (На самом деле это не так: они называются BaseLogger.LogName и SpecificLogger.LogName. Но поскольку в C# нам не всегда нужно квалифицировать имя члена с классом, похоже, что они одно и то же.)
.NET решает сделать 3. (и он делает это с как в статике и не-статикой Если вы хотите поведение 2 -. замена - с не-статики, то база должна быть virtual
и производный класс должен отметить метод как override
, чтобы было ясно, что они сознательно переопределяют метод в базовом классе. C# никогда не сделает метод производного класса заменяет метод базового класса, если только производный класс явно не заявил, что это то, что они хотел.) Это, вероятно, будет безопасным, потому что два члена являются unrelat ed - базовое LogName не существовало даже в том месте, где был введен производный. И это предпочтительнее просто ломать, потому что в последней версии базового класса появился новый член.
Без этой функции в новых версиях .NET Framework невозможно было бы добавить новых членов в существующие базовые классы, не нарушая их.
Вы говорите, что поведение не то, что вы ожидаете. На самом деле это именно то, что я ожидаю, и то, что вы, вероятно, захотите на практике. BaseLogger не знает, что SpecificLogger внедрил собственное свойство LogName. (Нет механизма, с помощью которого он мог бы, потому что вы не можете переопределить статические методы.) И когда автор SpecificLogger написал это свойство LogName, помните, что они писали против v1 BaseLogger, у которого не было логического имени, поэтому они не предполагали, что он также должен заменить базовый метод. Поскольку ни один класс не хочет замены, очевидно, что замена будет неправильной.
Единственный сценарий, в котором вы должны столкнуться в этой ситуации, состоит в том, что два класса находятся в разных компонентах. (Очевидно, вы можете придумать сценарий, когда они находятся в одном компоненте, но почему бы вам это сделать? Если вы владеете обоими частями кода и выпускаете их в одном компоненте, было бы безумно делать это.) И поэтому BaseLogger должен получить свое собственное свойство LogName, что и происходит именно так. Вы, возможно, написал:
SpecificLogger.Log("test");
но C# компилятор видит, что SpecificLogger не предоставляет метод журнала, так получается это в:
BaseLogger.Log("test");
, потому что это, где определен метод входа.
Таким образом, всякий раз, когда вы определяете метод в производном классе, который не пытается переопределить существующий метод, компилятор C# указывает это в метаданных. (В метаданных метода указано, что этот метод должен быть совершенно новым, не связанным ни с чем в базовом классе.)
Но это дает вам проблему, если вы хотите перекомпилировать CompD. Допустим, у вас есть отчет об ошибке из-за совершенно несвязанного бита кода, и вам нужно выпустить новую версию CompD. Вы скомпилируете его с новой версией CompB. Если код, который вы написали, не был разрешен, вы на самом деле не сможете - старый код, который уже скомпилирован, будет работать, но вы не сможете скомпилировать новые версии этого кода, что было бы немного сумасшедшим ,
Итак, чтобы поддержать этот (откровенно несколько неясный) сценарий, они позволяют вам это делать. Они генерируют предупреждение, чтобы вы знали, что у вас есть именование. Вам нужно поставить ключевое слово new
, чтобы избавиться от него.
Это неясный сценарий, но если вы хотите поддерживать наследование по границам компонентов, вам это нужно, иначе добавление новых открытых или защищенных членов в базовый класс неизменно будет изменением. Вот почему это здесь. Но это плохая практика, когда-либо полагаться на нее, следовательно, на то, что вы получаете предупреждение о компиляторе. Использование ключевого слова new
, чтобы избавиться от предупреждения, должно быть всегда остановлено.
Суть в том, что эта функция существует только по одной причине, и это должно вывести вас из отверстия в ситуациях, когда новая версия некоторого базового класса добавила элемент, который ранее не существовал, и который сталкивается с членом, который уже находится в вашем производном классе. Если это не та ситуация, в которой вы находитесь, не используйте эту функцию.
(я думаю, что они фактически должны выдавать сообщение об ошибке, а не предупреждение, когда вы выходите из нового, чтобы сделать это более ясным.)
Как говорили другие, это не является переопределяющим - и оно делает точно, как я ожидал. Пожалуйста, не думайте, что все думают так же, как вы. –