Подтвердить что ты не робот

Почему методы в С# не являются автоматически виртуальными?

Возможный дубликат:
Почему С# реализует методы как не виртуальные по умолчанию?

Было бы гораздо меньше работать, чтобы определить, какие методы НЕ переопределяемы, а не переопределяемы, потому что (по крайней мере для меня), когда вы разрабатываете класс, вам все равно, будут ли его наследники переопределять ваши методы или нет...

Итак, почему методы в С# не являются автоматически виртуальными? В чем смысл этого?

4b9b3361

Ответ 1

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

Решение о том, какие методы делать виртуальные должно быть преднамеренным, продуманным решением - не то, что происходит автоматически - так же, как и любые другие решения, касающиеся публичной поверхности вашего API.

Ответ 2

Андерс Хейлсберг ответил на этот вопрос в этом интервью, и я цитирую:

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

Более важной проблемой является управление версиями. Есть две школы мысли о виртуальные методы. Академическая школа мысли говорит: "Все должно быть виртуальный, потому что я, возможно, захочу когда-нибудь переопределите его". Прагматичный школа мысли, которая исходит из создание реальных приложений, работающих в реальный мир, говорит: "Мы должны быть действительно заботясь о том, что мы делаем виртуальная".

Когда мы делаем что-то виртуальное в платформе, мы делаем очень много promises о том, как он развивается в будущее. Для не виртуального метода мы обещайте, что когда вы позвоните метод, x и y. Когда мы публиковать виртуальный метод в API, мы не только обещают, что, когда вы позвоните этот метод, x и y произойдет. Мы также обещаю, что когда вы переопределите этот метод, мы будем называть это в этом особая последовательность в отношении эти другие и государство будут в этом и том инварианте.

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

Ответ 3

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

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

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

Ответ 4

Конвенция? Думаю, ничего больше. Я знаю, что Java автоматически делает методы виртуальными, а С# - нет, поэтому на каком-то уровне явно есть некоторые разногласия относительно того, что лучше. Лично я предпочитаю С# default - считаю, что переопределяющие методы намного реже, чем не переопределять их, поэтому было бы более кратким определять явно виртуальные методы.

Ответ 6

Чтобы перефразировать Эрик Липперт, один из парней, которые разработали С#: Таким образом, код не становится случайно сломанным, когда исходный код, полученный вами от третьего лица, изменяется. Другими словами, чтобы предотвратить проблему Хрупкий базовый класс.

Если метод должен быть виртуальным, если потому, что вы (предположительно) приняли сознательное решение разрешить замену функции, ее спроектировали, протестировали и документировали. Что произойдет, если, скажем, вы сделали функцию "frob", а в некоторой последующей версии разработчики базового класса решили также сделать функцию "frob"?

Ответ 7

Итак, ясно, разрешаете ли вы переопределять или метод или принудительно скрывать метода (с помощью ключевого слова new).

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

Ответ 8

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

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

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

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

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

Ответ 9

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

Ответ 10

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

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

Ответ 11

Потому что это не Java

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

Ответ 12

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