Почему нам нужно новое ключевое слово и почему поведение по умолчанию скрывается и не переопределяется?
Я смотрел на это блоге и были следующие вопросы:
- зачем это нужно
new
ключевое слово, это просто указать, что метод базового класса скрывается. Я имею в виду, зачем нам это нужно? Если мы не используемoverride
ключевое слово, разве мы не скрываем метод базового класса? - почему значение по умолчанию в C# скрывается и не переопределяется? Почему дизайнеры реализовали его именно так?
8 ответов:
хорошие вопросы. Позвольте мне переформулировать их.
почему это законно, чтобы скрыть метод с другим методом вообще?
позвольте мне ответить на этот вопрос с примером. У вас есть интерфейс от CLR v1:
interface IEnumerable { IEnumerator GetEnumerator(); }
супер. Теперь в CLR v2 у вас есть дженерики, и вы думаете: "человек, если бы у нас были дженерики в v1, я бы сделал это общим интерфейсом. Но я не стала. Я должен сделать что-то совместимое с ним сейчас, что и универсальный, так что я получаю преимущества дженериков без потери обратной совместимости с кодом, который ожидает IEnumerable интерфейс."
interface IEnumerable<T> : IEnumerable { IEnumerator<T> .... uh oh
что вы собираетесь назвать GetEnumerator метод
IEnumerable<T>
? Помни, ты хочу его, чтобы скрыть getenumerator для неуниверсальных базовый интерфейс. Ты никогда хотите, чтобы эта вещь была вызвана, если вы явно не находитесь в ситуации обратного сравнения.это само по себе оправдывает метод скрытия. Для большего количества мыслей об обоснованиях метода скрытия см. моя статья на эту тему.
почему скрытие без "нового" вызывает предупреждение?
потому что мы хотим обратить ваше внимание, что вы что-то скрываете и, возможно, делаете это случайно. помните, что вы можете скрывать что-то случайно из-за редактирования базового класса, выполненного кем-то другим, а не путем редактирования производного класса.
почему скрывается без "нового" предупреждение, а не ошибка?
по той же причине. Вы можете скрывать что-то случайно, потому что вы только что выбрали новую версию базового класса. Это происходит постоянно. FooCorp создает базовый класс B. BarCorp создает производный класс D с помощью панели методов, потому что их клиентам нравится этот метод. FooCorp видит это и говорит: Эй, это хорошая идея, мы можем поместить эту функциональность в базовый класс. Они делают это и отправляют новую версию из Фу.DLL, и когда BarCorp поднимает новую версию, было бы неплохо, если бы им сказали, что их метод теперь скрывает метод базового класса.
мы хотим, чтобы эта ситуация была предупреждение, а не потому что ошибка означает, что это еще одна форма проблемы хрупкого базового класса. C# был тщательно разработан таким образом, что когда кто-то вносит изменения в базовый класс, последствия для кода, использующего производный класс, являются свернутый.
почему скрывается и не переопределяет значение по умолчанию?
потому что виртуальное переопределение опасно. Виртуальное переопределение позволяет производным классам изменять поведение кода, который был скомпилирован для использования базовых классов. Делаешь что-то опасное, как сделать переопределение должно быть то, что вы делаете сознательно и сознательно, не случайно.
Если методу в производном классе предшествует ключевое слово new, то метод определяется как независимый от метода в базовом классе
однако если вы не укажете ни new, ни overrides, результат будет таким же, как если бы вы указали new, но вы получите предупреждение компилятора (поскольку вы можете не знать, что вы скрываете метод в методе базового класса, или действительно Вы, возможно, хотели его переопределить и просто забыли включить метод ключевое слово.)
таким образом, это поможет вам избежать ошибок и явно показать, что вы хотите сделать, и это делает более читаемый код, так что можно легко понять ваш код.
стоит отметить, что только эффект
new
в этом контексте, чтобы подавить предупреждение. Нет никаких изменений в семантике.Итак, один ответ: Нам нужно
new
чтобы сообщить компилятору, что скрывается намеренно и избавиться от предупреждения.следующий вопрос: если вы не можете / не можете переопределить метод, зачем вводить другой метод с тем же именем? Потому что прячется внутри суть имени-конфликт. И вы, конечно, избежать его в большинстве случаев.
в C# члены запечатаны по умолчанию означает, что вы не можете переопределить их (если не помечены
virtual
илиabstract
ключевые слова) и это для производительности. Элемент новый модификатор используется для явного скрытия наследуемого элемента.
если переопределение было по умолчанию без указания
override
ключевое слово, вы можете случайно переопределить какой-то метод вашей базы только из-за равенства имен.стратегия компилятора .Net заключается в том, чтобы выдавать предупреждения, если что - то может пойти не так, просто для безопасности, поэтому в этом случае, если переопределение было по умолчанию, для каждого переопределенного метода должно быть предупреждение-что-то вроде "предупреждение: проверьте, действительно ли вы хотите переопределить".
мое предположение в основном связано с множественным наследованием интерфейса. Использование дискретных интерфейсов было бы очень возможно, что два различных интерфейса используют одну и ту же сигнатуру метода. Разрешение на использование
new
ключевое слово позволит вам создавать эти различные реализации с одним классом, вместо того, чтобы создавать два разных класса.Обновлено ... Эрик дал мне идею о том, как улучшить этот пример.
public interface IAction1 { int DoWork(); } public interface IAction2 { string DoWork(); } public class MyBase : IAction1 { public int DoWork() { return 0; } } public class MyClass : MyBase, IAction2 { public new string DoWork() { return "Hi"; } } class Program { static void Main(string[] args) { var myClass = new MyClass(); var ret0 = myClass.DoWork(); //Hi var ret1 = ((IAction1)myClass).DoWork(); //0 var ret2 = ((IAction2)myClass).DoWork(); //Hi var ret3 = ((MyBase)myClass).DoWork(); //0 var ret4 = ((MyClass)myClass).DoWork(); //Hi } }
Как уже отмечалось, метод/свойство скрытия позволяет изменить вещи о методе или свойстве, которые не могут быть легко изменены в противном случае. Одна из ситуаций, когда это может быть полезно, позволяет унаследованному классу иметь свойства чтения-записи, которые доступны только для чтения в базовом классе. Например, предположим, что базовый класс имеет набор свойств только для чтения, называемых Value1-Value40 (конечно, реальный класс будет использовать лучшие имена). Запечатанный потомок этого класса имеет конструктор, который принимает объект базового класса и копирует оттуда значения; класс не позволяет их изменять после этого. Другой наследуемый потомок объявляет свойства чтения-записи, называемые Value1-Value40, которые при чтении ведут себя так же, как версии базового класса, но при записи позволяют записывать значения. Конечным эффектом будет тот код, который хочет, чтобы экземпляр базового класса, который, как он знает, никогда не изменится, мог создать новый объект класса только для чтения, который может копировать данные из переданного объекта без необходимости беспокоиться о том, является ли этот объект только для чтения или для чтения-записи.
одна неприятность с этим подходом-возможно, кто-то может мне помочь-заключается в том, что я не знаю способа как тени, так и переопределить определенное свойство в одном классе. Позволяет ли это какой-либо из языков CLR (я использую vb 2005)? Было бы полезно, если бы объект базового класса и его свойства могли быть абстрактными, но для этого потребовался бы промежуточный класс для переопределения Value1 Value40 свойства, прежде чем класс-потомок может затенять их.
вы правы, что новое ключевое слово явно скрывает член из базового класса, так что вызывающие абоненты в конечном итоге используют член в вашем подклассе, а не версию суперкласса. Поскольку это сообщение в блоге также упоминает,вы можете неявно сделать это.
это отличается от переопределения члена базового класса; для этого член базового класса должен быть помечен как абстрактный или виртуальный. Поэтому не каждый член базового класса может быть переопределен. Предположим, вы подкласс класса из чужая сборка, и у вас нет доступа или вы не хотите возвращаться и модифицировать этот код, чтобы сделать членов виртуальными. Без нового ключевого слова вы бы застряли.
вы можете спорить, лучше ли иметь ключевое слово и быть явным (мое мнение) или просто делать это неявно.