C# скрытие методов

serega1604

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

stm6692945

оракла на вас не хватает , шарпаебы

zorin29

А мне объясните, пожалуйста, что значит скрытие методов :)

serega1604

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
class X1
{
public void test1
{
Console.WriteLine("xx");
}

}
class X2:X1
{
public new void test1
{
Console.WriteLine("xy");
}
}
class Program
{
static void Main(string[] args)
{
X2 test2 = new X2;
test2.test1;
X1 test1 = test2;
test1.test1;
Console.ReadKey;
}
}
}

это когда вот такой код выдает
xy
xx
вместо ожидаемых
xy
xy
т.е. то, какой метод вызовется зависит не от класса объекта, а от класса переменной.
ЗЫ: насчет терминологии - как в книжке написано, так я и написал, английского термина не знаю.

oliver11

этож нарушение полиморфизма
Хочешь полиморфизм — пиши virtual/override явно.
и от него становится код становится менее читабельным и понимаемым?
В C++ поведение ровно такое же. Никто не жалуется.

zorin29

Собственно, да. Если тебе нужен полиморфизм - пиши virtual.
Мне кажется, это наследие c++, когда иногда было очень важно, что метод НЕ виртуальный (соответственно, нет обращения к VMT и работает быстрее).
Другого use-case для невиртуальных методов я пока не могу придумать...

val63

Ну это ж ясно.
Чтобы задавать на собеседованиях коварные вопросы.

Serab

Хз, мне в этом видится дополнительная гибкость языка на случай, когда надо адаптировать (повторно использовать, скажем) классы из сторонней библиотеки и тебе нужны методы с теми же именами. Ну типа просто на всякий случай. А полиморфизм вот вообще не в тему. Т.е. писать-то так внутри собственного проекта наверное и не надо, но иметь возможность в экстренной ситуации так сделать наверное хотелось бы.

oliver11

Виртуальность метода ещё сильно сокращает возможности по его встраиванию в места вызова. JIT-у приходится либо слишком много знать о программе, либо сильно извращаться (судя по статьям авторов JIT в JVM от IBM чтобы что-то куда-то встроить.
Так что невиртуальность методов по умолчанию — вполне правильный выбор с точки зрения эффективности.

serega1604

>В C++ поведение ровно такое же. Никто не жалуется.
C++ - недоязык, и все это знают.
ну раз в C# решили нагородить костылей ради совместимости с плюсами - пусть так и будет.

serega1604

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

zorin29

невиртуальность методов по умолчанию — вполне правильный выбор с точки зрения эффективности.
ИМХО, с этой же самой точки зрения C# - не вполне правильный выбор языка :) Если нужна эффективность - надо писать на Си, разве нет?

zorin29

как раз если так и писать - то только _внутри_ проекта, чтобы никто извне не мог твоими классами воспользоваться, ибо начнется ахтунг, деление на 0 и конец света.
ничего не понял. Как невиртуальные методы помогут запретить пользоваться твоими классами?

oliver11

Если можно не пессимизировать, лучше не пессимизировать. :-)

serega1604

>ничего не понял. Как невиртуальные методы помогут запретить пользоваться твоими классами?
а так, что пользоваться переопределенными методами в унаследованных от твоих классах будет опасно, ибо неясно, когда будет вызываться твои методы, а когда - базового типа.
т.е. либо уж делать sealed, либо virtual.

zorin29

а так, что пользоваться переопределенными методами в унаследованных от твоих классах будет опасно, ибо неясно, когда будет вызываться твои методы, а когда - базового типа.т.е. либо уж делать sealed, либо virtual.
Ты сам ответил на свой вопрос. Для запрета наследования от твоих классов надо писать sealed. А невиртуальные методы тут не при чем.

serega1604

>Для запрета наследования от твоих классов надо писать sealed. А невиртуальные методы тут не при чем.
а что тогда тут? хочешь невиртуального метода - пиши sealed, хочешь виртуального - пиши virtual. нахера нужна лишняя сущность, от которой я пока что вижу сплошные проблемы?
ЗЫ: в плюсах, насколько я помню, есть множественное наследование, поэтому там, возможно, подобное поведение имеет смысл.

zorin29

а что тогда тут? хочешь невиртуального метода - пиши sealed, хочешь виртуального - пиши virtual. нахера нужна лишняя сущность, от которой я пока что вижу сплошные проблемы?
Уже два предложения есть:
1) Невиртуальные методы эффективнее.
2) Нужно определить новый метод с той же сигнатурой, но совершенно другим поведением.

Dasar

>а что тогда тут? хочешь невиртуального метода - пиши sealed, хочешь виртуального - пиши virtual. нахера нужна лишняя сущность, от которой я пока что вижу сплошные проблемы?
new нужен только на случай следующего сценария
в библиотеке есть класс A
от него унаследован свой класс B и в нем определен метод F
через некоторое время выходит новая версия класса A, в которой вдруг появился свой метод F, который никакого отношения к методу B.F не имеет.
и теперь чтобы не было путаницы метод F в классе B имеет смысл пометить new
ps
и соответственно new никакого отношения к виртуальности/невиртуальности или sealed не имеет.

serega1604

>new нужен только на случай следующего сценария
>в библиотеке есть класс A
>от него унаследован свой класс B и в нем определен метод F
>через некоторое время выходит новая версия класса A, в которой вдруг появился свой метод F, который никакого отношения к методу B.F не имеет.
>и теперь чтобы не было путаницы метод F в классе B имеет смысл пометить new
ясно, спасибо.
>и соответственно new никакого отношения к виртуальности/невиртуальности или sealed не имеет.
это не ко мне, не я тут начал про виртуальность затирать.

ms_nadin

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

kill-still

на правах КО попробую объяснить на пальцах:
чтобы понять "нахуя", как вы выразилсь, надо знать как внутри оно устроено.
в Х2 "старый" метод test1 никуда не девается. ты лишь заслоняешь его имя.
допустим ты можешь в Х2 определить метод test1_old и вызвать в нем унаследованный test1 родителя(Х1).
если заменять код, реализующий метод test1 полностью, такого не получится сделать.
а когда ты обращаешься к объекту Х2 через переменную типа Х1 у тебя просто вызывается этот "старый" код, который никуда не девался, как я уже говорил.
в делфи также есть заслонение и в яве (вроде) тоже.

Dmitriy82

И как это приближает нас к пониманию "нахуя"?

kill-still

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

kill-still

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

serega1604

>заслонение само по себе необходимо например для изменения сигнатур.
чо-чо? и как мы скроем метод с другой сигнатурой?

serega1604

>в яве (вроде) тоже.
по крайней мере я не встречал.

kill-still

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

serega1604

а ты не думаешь, что в этом случае ты просто напишешь метод с другой сигнатурой, и никакого скрытия тут не будет?
ну или ты под сигнатурой что-то своё, особенное, подразумеваешь.

Serab

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

kill-still

Ну хз как там во всей этой схолистикой, но "старый" метод со старой сигнатурой в ребенке больше не будет виден.

zorin29

не знаю как в шарпе, а в дельфях просто убираешь ключевое слово override и можно менять сигнатуру метода. я думаю в этом отношении они не сильно отличаются.
Ты думаешь неправильно :)
В C# нет ключевого слова overload, и новый метод с тем же именем (но другими параметрами) не заслонит старый, а будет существовать наряду с ним.
И вообще, что за мода высказывать суждения о языке, которого не знаешь? :)

serega1604

напиши мне псевдокод (ну или пример на дельфи, если уж совсем тяжко) изменения сигнатуры с get(int) на set(Object).

Dasar

>Ну хз как там во всей этой схолистикой, но "старый" метод со старой сигнатурой больше не будет виден.
это лишь видимость скрытия
в любой момент его можно вызвать через X1)new X2.test1;

Serab

В C# нет ключевого слова overload
он говорил про слово override, которое в C# есть, но просто убрать его там нельзя, но можно заменить на new со схожими последствиями.

kill-still

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

Serab

подобное желание свидетельствует о кривой архитектуре.
мозга?

kill-still

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

kill-still

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

kill-still

сигнатуру метода составляет его имя и последовательность типов параметров
т.е. изменение типов параметров тоже является изменением сигнатуры.
или где?

serega1604

>т.е. изменение типов параметров тоже является изменением сигнатуры.
ну да, а что тебя смущает?

serega1604

>з.ы. в яве, насколько я помню, вообще вроде все методы виртуальные.
насколько я тут понял, аналогом невиртуального метода в яве будет final, если у родителя метода с такой сигнатурой нет.

kill-still

имхо ничего общего.

serega1604

>имхо ничего общего.
и в чем же разница?

zorin29

В C# нет ключевого слова overload
он говорил про слово override, которое в C# есть...
Я прекрасно понимаю, о чем он говорил, потому что писал 6 лет на Delphi и год на C#. Отличие у Delphi и C# в том, что по умолчанию в Delphi нет перегруженных методов: можно определить только один метод с данным именем. Если тебе хочется еще методов - изволь КАЖДЫЙ перегруженный метод пометить словом overload.
Соответственно, если у тебя был, скажем метод

type TParent = class
public:
procedure Init(path: String); virtual;
end;

А ты хочешь, чтобы в твоем наследнике Init принимал в качестве аргумента, скажем, TStringList, то надо написать:

type TChild = class (TParent)
public:
procedure Init(values: TStringList); reintroduce;
end;

При этом унаследованный Init будет "затерт" новым методом:

var
 child: TChild;
...
 child = TChild.Create;
 child.Init('c:\config.txt');

вернет ошибку компиляции.
Ключевое слово reintroduce, как мне кажется, необязательное.

Serab

А, понял теперь :)

kill-still

без reintroduce у тебя хинт вылезет, что ты заслонил/затенил (по англицки hide) виртуальный метод.

zya369

рассуждал про общие принципы ооп

Оставить комментарий
Имя или ник:
Комментарий: