Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.78/9: Рейтинг темы: голосов - 9, средняя оценка - 4.78
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3

Нежданчик в наследовании

01.10.2018, 17:17. Показов 2198. Ответов 41
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
или стреляем себе в ногу с помощью C#

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
        static void Main(string[] args)
        {
            //CheckServiceProtocol();
 
            var b = new B();
            b.Test(); // False
            b.Run(); // True
            b.Run2(); //False
 
            A a = b;
            a.Test(); // True (!)
            a.Run(); // True
        }
 
    abstract class A
 
    {
        public virtual void Test(bool v = true)
        {
            Console.WriteLine(v);
        }
 
        public void Run()
        {
            Test();
        }
    }
 
    class B : A
    {
        public override void Test(bool v = false)
        {
            Console.WriteLine(v);
        }
 
        public void Run2()
        {
            Test();
        }
    }
В принципе логика понятна (компилятор просто подставляет переменую во время компиляции из "текущего" класса), но я бы ожидал более строгого следования контракту...
5
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
01.10.2018, 17:17
Ответы с готовыми решениями:

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

Конструктор при наследовании
Здравствуйте. Нужно унаследовать класс B от класса A, при этом конструктор в классе B должен принимать объект класса A в качестве...

Ошибка в наследовании классов
есть 2 класса , один должен наследовать другой вот первый класс struct people { public string surname, name,...

41
1536 / 544 / 127
Регистрация: 09.01.2018
Сообщений: 1,768
02.10.2018, 16:06
Студворк — интернет-сервис помощи студентам
Sanya_sa,
Неверно. Есть базовый класс родитель и метод имеется только у него. У наследника он виден лишь потому, что наследник наследует методы родителя. Но сам он никакого метода не объявлял, он его унаследовал. И переопределил. А у кого он переопределяется? Метод принадлежит родителю, у него он и будет переопределен. Наследник только наследует, своей реализации он не объявлял. Отсюда выходит, что невозможно вызвать старую реализацию метода родителя. Потому что ее переопределил наследник.
0
 Аватар для Sanya_sa
913 / 817 / 333
Регистрация: 03.02.2015
Сообщений: 5,276
Записей в блоге: 9
02.10.2018, 16:06
Цитата Сообщение от kolorotur Посмотреть сообщение
Wolfdp, Элд Хасп, пришла в голову мысль: возможно, у нас расхождения во мнениях касательно адекватности текущего поведения из-за разного восприятия семантики значений по умолчанию.
Если рассматривать вызов метода со значением по умолчанию как "да используй какое хочешь значение — мне все равно", то текущее поведение действительно странно.
Если же его рассматривать как "меня заявленное значение устраивает", то поведение вполне логично.
Ну скажу так в данном примере для меня поведение ожидаемо. Если даже я юзаю библиотеку то при переопределнии, должен смотреть документацию (как реализован метод Test в нашем случаи в базовом классе), дума даже инталисенс подскажет.
0
 Аватар для Sanya_sa
913 / 817 / 333
Регистрация: 03.02.2015
Сообщений: 5,276
Записей в блоге: 9
02.10.2018, 16:09
Ну да, все видно.
Миниатюры
Нежданчик в наследовании  
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
02.10.2018, 16:16
Цитата Сообщение от Sanya_sa Посмотреть сообщение
Если даже я юзаю библиотеку то при переопределнии, должен смотреть документацию (как реализован метод Test в нашем случаи в базовом классе)
Совершенно верно.
И будете вполне оправданно предполагать, что метод будет вызван с тем значением, о котором вы прочитали в документации.

Когда мы используем статический метод Create типа XmlWriter, мы не можем знать, не лазя в исходники, что нам будет возвращена ссылка на экземпляр одного из нижеследующих типов:
  • XmlUtf8RawTextWriterIndent
  • XmlUtf8RawTextWriter
  • XmlAutoDetectWriter
  • HtmlUtf8RawTextWriterIndent
  • HtmlUtf8RawTextWriter
  • XmlEncodedRawTextWriterIndent
  • XmlEncodedRawTextWriter
  • HtmlEncodedRawTextWriterIndent
  • HtmlEncodedRawTextWriter
  • TextEncodedRawTextWriter
  • QueryOutputWriter
  • XmlWellFormedWriter
  • XmlAsyncCheckWriter

Все они наследуются от XmlWriter и при этом имеют модификатор доступа internal, а значит о них ни слова в документации.
И если в XmlWriter объявлен какой-то виртуальный метод со значениями по умолчанию, то можно себе представить вакханалию, которая будет твориться при его переопределении.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
02.10.2018, 16:17
Цитата Сообщение от kolorotur Посмотреть сообщение
Если рассматривать вызов метода со значением по умолчанию как "да используй какое хочешь значение — мне все равно", то текущее поведение действительно странно.
Если же его рассматривать как "меня заявленное значение устраивает", то поведение вполне логично — потому что разработчик будет рассчитывать на то, что во время выполнения будет использоваться то же значение, которое его устроило во время написания кода.
Надо ещё раз всё переварить......
0
1123 / 794 / 219
Регистрация: 15.08.2010
Сообщений: 2,185
02.10.2018, 16:23
Цитата Сообщение от Sanya_sa Посмотреть сообщение
Ну да, все видно.
ну почти)
Миниатюры
Нежданчик в наследовании   Нежданчик в наследовании  
0
 Аватар для Sanya_sa
913 / 817 / 333
Регистрация: 03.02.2015
Сообщений: 5,276
Записей в блоге: 9
02.10.2018, 17:21
Наверное все таки не логично.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var b = new B();
b.Test();
b.Run();
 
A a = b;
a.Test(); 
a.Run();
 
 
 
abstract class A
{
    public virtual void Test(bool v = true)
    {
        Console.WriteLine(v);
    }
 
    public virtual void Run()
    {
        Test();
    }
}
 
class B : A
{
    public override void Test(bool v = false)
    {
        Console.WriteLine(v);
    }
 
    public override void Run()
    {
        Test();
    }
}
False
False
True
False
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
02.10.2018, 17:28
Цитата Сообщение от Sanya_sa Посмотреть сообщение
Наверное все таки не логично.

Вот так более логично бы выглядело?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
var b = new B();
b.Test();
b.Run();
 
A a = b;
a.Test(); 
a.Run();
 
 
 
abstract class A
{
    public virtual void Test(bool v)
    {
        Console.WriteLine(v);
    }
    public void Test() => Test(true);
 
    public virtual void Run()
    {
        Test(true);
    }
}
 
class B : A
{
    public override void Test(bool v)
    {
        Console.WriteLine(v);
    }
   new public void Test() => Test(false);
 
    public override void Run()
    {
        Test(false);
    }
}
Вот выше то же самое.
Вы путаетесь потому, что смотрите на оба типа "с высоты птичьего полета" и видите реализацию обоих.
Разнесите классы по разным сборкам и смотрите на код каждого отдельно от другого, как если бы вы его писали в данный момент.
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
02.10.2018, 17:29
Цитата Сообщение от Sanya_sa Посмотреть сообщение
Наверное все таки не логично.
Да все логично...
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
abstract class A
{
    public virtual void Test(bool v = true)
    {
        Console.WriteLine(v);
    }
 
    public virtual void Run()
    {
        Test(); // == Test(true)
    }
}
 
class B : A
{
    public override void Test(bool v = false)
    {
        Console.WriteLine(v);
    }
 
    public override void Run()
    {
        Test(); // == Test(false);
    }
}
0
 Аватар для Sanya_sa
913 / 817 / 333
Регистрация: 03.02.2015
Сообщений: 5,276
Записей в блоге: 9
02.10.2018, 17:31
Так, ладно. Нужно с этой мыслью переспать.
Уже запутался окончательно. )
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
02.10.2018, 17:36
Возможно, вам и это покажется нелогичным
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
interface IFace
{
    void Print();
}
 
class A : IFace
{
    public void Print()
    {
        Console.WriteLine("IFace.A");
    }
}
 
class B : A, IFace
{
    public new void Print()
    {
        Console.WriteLine("IFace.B");
    }
}
 
void Main()
{
    new A().Print(); // IFace.A
    new B().Print(); // IFace.B
    (new B() as IFace).Print(); // IFace.B
    (new B() as A).Print(); // IFace.A
    (new B() as A as IFace).Print(); // IFace.B
}
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
02.10.2018, 17:58
Цитата Сообщение от Sanya_sa Посмотреть сообщение
Нужно с этой мыслью переспать.
Что-то мне кажется, что пока что эта мысль тут со всеми участниками темы переспала
3
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
02.10.2018, 18:09
Цитата Сообщение от kolorotur Посмотреть сообщение
Что-то мне кажется, что пока что эта мысль тут со всеми участниками темы переспала
И одного раза будет мало....
0
Эксперт .NET
 Аватар для Usaga
14807 / 9580 / 1368
Регистрация: 21.01.2016
Сообщений: 36,088
02.10.2018, 18:14
kolorotur, кстати, раз пошло обсуждение "тонкостей" языка, то не могли бы вы прокомментировать данный код:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;
 
namespace Experiments
{
    public class Some
    {
        public static readonly Some s = new Some();
 
        //static Some()
        //{
        //    Console.WriteLine("sctor");
        //}
 
        public Some()
        {
            Console.WriteLine("ctor");
        }
 
        public void Do()
        {
        }
    }
 
    class Program
    {
        static void Main()
        {
            Some.s.Do();
 
            Console.ReadKey();
        }
    }
}
Недавно наткнулся на подобный код (это упрощённый вариант) в проекте. Интересная (что меня очень сильно удивило) особенность в том, что в такой подаче, статическая инициализация начинается не при первом обращении к типу Some (Some.s.Do()), а при входе в scope с этим типом.

Т.е. строка public static readonly Some s = new Some(); выполняется при входе в метод Main, но до первой строки кода в нём. Если же расскомментировать статический конструктор, то поведение возвращается к ожидаемому: статическая инициализация начинает при обращении к типу Some. Я не смог нагуглить (я шибко и не старался) разъяснений по этому поведению.

Что интересно, что в .NET Core всё работает как и ожидается.
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
02.10.2018, 19:24
Usaga, это прописано в спецификации языка C#
The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration. If a static constructor (§10.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.
The execution of a static constructor is triggered by the first of the following events to occur within an application domain:

An instance of the class type is created.
Any of the static members of the class type are referenced.
В вашем коде нет статического конструктора, следовательно инициализатор может выполниться когда угодно (но до использования какого-либо статического поля этого класса).
1
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
02.10.2018, 19:25  [ТС]
TopLayer, вы тоже путаете саму перегрузку/переназначение и передаваемые параметры )

kolorotur, вы путаете мою мысль "нужно жестко ограничить" с "так не должно работать". То что "перегрузить" параметр по умолчанию нельзя, понятно и ежу -- он там прибит железобетонно. Мое "недовольство" вызвано именно возможностью подставить новое значение в "новом" методе. Дело в том, что большинство кода пишется абстракцией, и работаешь чаще с черным ящиком. И когда перегружаешь, то ожидаешь что в общем коде будет работать "по новому", а на самом деле нужно помнить что там не просто пустой вызов, а с явной передачей параметра (внезапно блин). Явность даного ньюанса где-то на том же уровне, что и н"еподгружаемостью" измененой константьі из другой сборки.

Как по мне, логично было бы именно ограничить возможность переопределять базовый метод только с тем же контрактом переменых по-умолчанию. В таком случае казус технически не возможен.
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
02.10.2018, 19:31
Цитата Сообщение от Wolfdp Посмотреть сообщение
TopLayer, вы тоже путаете саму перегрузку/переназначение и передаваемые параметры )
Почему это?
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
02.10.2018, 19:41
Usaga, товарищ TopLayer выше верно написал: если статический конструктор не объявлен, то инициализация отдается на откуп рантайму. До четвертой версии рантайма он производил инициализацию тогда, когда джиттерил первый метод, который обращался к статическим полям или создавал экземпляр этого класса.
В более поздних версиях он расслабился еще больше: например, может производить инициализацию хоть при запуске приложения или непосредственно при обращении — на свое усмотрение.

Цитата Сообщение от Wolfdp Посмотреть сообщение
вы путаете мою мысль "нужно жестко ограничить" с "так не должно работать"
А, вон оно что.
Жестко ограничить не получится, потому что всегда есть возможность это обойти новой перегрузкой.

Цитата Сообщение от Wolfdp Посмотреть сообщение
Как по мне, логично было бы именно ограничить возможность переопределять базовый метод только с тем же контрактом переменых по-умолчанию. В таком случае казус технически не возможен.
При таком подходе всплывает проблема хрупкого базового класса: у вас проект на пару лямов строк и внезапно библиотека с базовым классом обновляется и в ней меняется дефолтное значение.
Поскольку у вас есть свой класс с переопределенным методом и старым значением, из-за запрета ваш проект перестает компилироваться — будьте добры снова оттестировать этот паролямовый проект.
С большой вероятностью вы просто матернетесь и сделаете тот же перегруженный метод без параметров, который вызывает переопределенный с нужным значением. Ну а если оно так тривиально решается, то зачем создавать разработчикам лишний головняк запретами?
1
Эксперт .NET
 Аватар для Wolfdp
3790 / 1767 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
02.10.2018, 23:19  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
и внезапно библиотека с базовым классом обновляется и в ней меняется дефолтное значение.
И перекомпелировать/перенабирать тебе все твое приложение заново. Тупо подсунув новую либу, получишь старое значение т.к. оно "вшито" в твой исходник. За изменение контракта нужно вводить закидывание тапками, а конкретно єтот кейс описан в Рихтере.

Тут правда задаюсь вопросом, а можно ли как-то технически ограничить контракт переменой по умолчанию? По ходу это же просто метаданые метода, и на готовом exe уже не отличишь переменую подсунутую компилятором из атрибута и явно проставленую руками. Т.е. остается только предупреждать
1
187 / 100 / 19
Регистрация: 15.09.2011
Сообщений: 801
03.10.2018, 02:59
Цитата Сообщение от kolorotur Посмотреть сообщение
Там же про плюсы.
Да, но ситуация аналогичная. Я собрал у себя аналог на плюсах - полная аналогия. Почитайте, что там народ в комментах пишет по этому поводу - я не буду тут умничать, так как настолько не разбираюсь в процессе компиляции. И про интерпретатор кода говорил, что он не даёт поставить not compile time переменную, ещё до этапа самой компиляции, в редакторе кода. Что там меня предупреждает - IntelliSence, кажись. Ну, и при самой компиляции, ясен перец, будет то же сообщение.

Добавлено через 4 минуты
Цитата Сообщение от kolorotur Посмотреть сообщение
И если в XmlWriter объявлен какой-то виртуальный метод со значениями по умолчанию, то можно себе представить вакханалию, которая будет твориться при его переопределении.
Вероятно, те, кто писал эти райтеры уже знали о поведении значений по умолчанию в виртуальных методах и просто не использовали такую возможность в своём коде. Так же следует и поступать нам на будущее - будем знать об этом подводном камне.

Добавлено через 47 минут
Интересный тут пост для "начинающих" получился)))
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
03.10.2018, 02:59

Вопрос о наследовании типов
Товарищи, подскажите пожалуйста static void Main() { object A = new string { "1", "2", "3" }; ...

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

Нюансы при наследовании
Такой пример: using System; using System.Collections.Generic; using System.Linq; using System.Text; using...

Создание Dictionary при наследовании
Проблема такова, есть абстрактный класс и собственно 2 наследника. Есть list типа базового класса. Как с помощью linq создать dictionary...

Вызов конструктора при наследовании
Как вызывается конструктор класса наследующегося другим классом. public class A { public A() { ... } } ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Запустил конкурс "тем и промптов для текстовых квестов созданных почти чисто ИИ"
Adler 06.10.2026
Всем привет! За последние три-четыре дня я создал более 16 текстовых квестовых игр используя преимущественно по одному запросу к ИИ на игру. Мне так понравилось смотреть все ветки/ сцены во всех. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru