Задать значение поля базового класса. C#
От: днс  
Дата: 03.03.09 19:10
Оценка:
Вот простенький примерчик:

using System;
 
public class BaseClass
{
   // объявили строковое поле
   public string MyStr;
  
   public BaseClass()
   {
      // в конструкторе используем объявленное выше поле
      System.Console.WriteLine(MyStr);
   }
}
 
 
public class Hello : BaseClass
{
    // тут я хочу присвоить значение полю базового класса
    base.MyStr = "Hello";
 
    public Hello():base(){}
}


Понятно, что этот пример даже не компилится. Он должен только пояснить суть вопроса.
Есть базовый класс, поля которого используются в конструкторе, а значения полей задаются в производных классах. Не подскажите, как это правильно делается?
Re: Задать значение поля базового класса. C#
От: vmpire Россия  
Дата: 03.03.09 19:31
Оценка:
Здравствуйте, днс, Вы писали:

днс>Понятно, что этот пример даже не компилится. Он должен только пояснить суть вопроса.

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

Виртуальными свойствами или методами. В шарпе их можно вызывать из конструктора.
Re: Задать значение поля базового класса. C#
От: rg45 СССР  
Дата: 03.03.09 19:43
Оценка: 4 (3) +3
Здравствуйте, днс, Вы писали:

днс>...

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

public class BaseClass
{
   public string MyStr;
  
   public BaseClass(string str)
   {
      MyStr = str;
      System.Console.WriteLine(MyStr);
   }
}
 
public class Hello : BaseClass
{
    public Hello() : base("Hello"){}
}
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: Задать значение поля базового класса. C#
От: днс  
Дата: 03.03.09 19:53
Оценка:
Здравствуйте, rg45, Вы писали:

R>
R>public class Hello : BaseClass
R>{
R>    public Hello() : base("Hello"){}
R>}
R>


Применимо к конкретному примеру, но плохо подходит, если вместо одного поля у нас имеется десяток структур.
Однако, всеравно спасибо, за участие в обсуждении.
Re[2]: Задать значение поля базового класса. C#
От: днс  
Дата: 03.03.09 20:14
Оценка:
Здравствуйте, vmpire, Вы писали:

V>Виртуальными свойствами или методами. В шарпе их можно вызывать из конструктора.


Спасибо, работает. Правда немножко смущает оформление в производных классах -- слишком громоздко получается,
но это, возможно, с непривычки. Однако подождем еще, вдруг предложат что-то неожиданное
Re[2]: Задать значение поля базового класса. C#
От: samius Япония http://sams-tricks.blogspot.com
Дата: 03.03.09 20:18
Оценка: 1 (1) +2
Здравствуйте, vmpire, Вы писали:

V>Здравствуйте, днс, Вы писали:


днс>>Понятно, что этот пример даже не компилится. Он должен только пояснить суть вопроса.

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

V>Виртуальными свойствами или методами. В шарпе их можно вызывать из конструктора.

Можно, но не нужно. Безопасно это можно сделать только в конструкторе sealed класса.
Re[3]: Задать значение поля базового класса. C#
От: vmpire Россия  
Дата: 03.03.09 20:34
Оценка: -1
Здравствуйте, samius, Вы писали:

V>>Виртуальными свойствами или методами. В шарпе их можно вызывать из конструктора.

S>Можно, но не нужно. Безопасно это можно сделать только в конструкторе sealed класса.
Да, вызывать виртуальные методы потомков sealed-класса — это круто
А что значит "безопасно"? Поля производного класса не будут проинициализированы в его конструкторе? Да, не будут и при написании вызовов виртуальных методов из конструктора это нужно учитывать. Но той опасности, которая была в C++ тут не будет согласно стандарту языка C#.
Re[4]: Задать значение поля базового класса. C#
От: samius Япония http://sams-tricks.blogspot.com
Дата: 03.03.09 20:58
Оценка: 2 (2) +1
Здравствуйте, vmpire, Вы писали:

V>Здравствуйте, samius, Вы писали:


V>>>Виртуальными свойствами или методами. В шарпе их можно вызывать из конструктора.

S>>Можно, но не нужно. Безопасно это можно сделать только в конструкторе sealed класса.
V>Да, вызывать виртуальные методы потомков sealed-класса — это круто
Про потомков я не говорил ни слова

V>А что значит "безопасно"? Поля производного класса не будут проинициализированы в его конструкторе? Да, не будут и при написании вызовов виртуальных методов из конструктора это нужно учитывать. Но той опасности, которая была в C++ тут не будет согласно стандарту языка C#.

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

О специфике виртуальных методов, вызываемых из конструктора базового класса, надо помнить не только при написании производных классов, а так же при рефакторинге. И если у меня в проекте 15Мб исходников, то мне помнить о таких дополнительных соглашениях некоторых классов довольно проблематично. А делать себе и коллегам пометки в коде "если обратишься к полю — ССЗБ" как-то несолидно.
Re[5]: Задать значение поля базового класса. C#
От: днс  
Дата: 03.03.09 21:10
Оценка:
Здравствуйте, samius, Вы написали много интересного и, наверное, правильного, но по существу: у вас есть другое решение проблемы?
Re[6]: Задать значение поля базового класса. C#
От: samius Япония http://sams-tricks.blogspot.com
Дата: 03.03.09 21:22
Оценка: 2 (1) +3
Здравствуйте, днс, Вы писали:

днс>Здравствуйте, samius, Вы написали много интересного и, наверное, правильного, но по существу: у вас есть другое решение проблемы?

Проблема мной до конца не понятна.

Если производный класс создается лишь для того, чтобы задать какие-то значения полям базового класса, то наследование тут вообще не лучший выход. Вместо наследования следует применить производящие методы, например так:
public static BaseClass CreateHello()
{
   return new BaseClass("Hello");
}


Если производный класс как-то расширяет базовый, то я бы избрал путь, который посоветовал rg45.

Смущает десяток структур — группируйте их в другие классы, либо разбивайте базовый на части.
Re: Задать значение поля базового класса. C#
От: днс  
Дата: 03.03.09 22:09
Оценка: 1 (1) :)
Еще разок пересмотрев архитектуру приложения, склонился к методу, предложенному rg45, который сначала не оценил.
Был не прав. Всем спасибо. Считаю вопрос исчерпан.
Re[5]: Задать значение поля базового класса. C#
От: vmpire Россия  
Дата: 04.03.09 10:59
Оценка:
Здравствуйте, samius, Вы писали:

V>>Да, вызывать виртуальные методы потомков sealed-класса — это круто

S>Про потомков я не говорил ни слова
Про потомков было в изначальном вопросе

V>>А что значит "безопасно"? Поля производного класса не будут проинициализированы в его конструкторе? Да, не будут и при написании вызовов виртуальных методов из конструктора это нужно учитывать. Но той опасности, которая была в C++ тут не будет согласно стандарту языка C#.

S>Вот и получается, что когда из конструктора базового класса вызываются виртуальные методы, то производные классы обрастают дополнительными контрактами по поводу того, как именно им нужно перекрывать виртуальные методы, к чему можно обращаться, а к чему — нет. И речь не только о полях производного класса, а и о всех его методах, которые могут обращаться к полям. Все эти методы будут работать во время конструктора не так, как они будут работать после вызова конструктора производного класса.
Замените в своих словах "виртуальные методы производных классов" на "невиртуальные методы того же класса", истинность высказывания не изменится. В любом случае программист должен следить, чтобы не было ошибочных обращений к неинициализированным переменным. Вызов именно виртуальных методов практически ничего к этой опасности не добавляет.
Наплодить ошибок можно в любой системе. А в вопросе речь шла о сравнительно простой логике, которой поля класса вообще не нужны.
Как жалко, что в C# нет модификатора параметров const как в C++

S>О специфике виртуальных методов, вызываемых из конструктора базового класса, надо помнить не только при написании производных классов, а так же при рефакторинге. И если у меня в проекте 15Мб исходников, то мне помнить о таких дополнительных соглашениях некоторых классов довольно проблематично. А делать себе и коллегам пометки в коде "если обратишься к полю — ССЗБ" как-то несолидно.

Документировать нетривиальные места кода теперь стало несолидно? Я что-то упустил в этой жизни?
Re[6]: Задать значение поля базового класса. C#
От: samius Япония http://sams-tricks.blogspot.com
Дата: 04.03.09 11:24
Оценка: 1 (1)
Здравствуйте, vmpire, Вы писали:

V>Замените в своих словах "виртуальные методы производных классов" на "невиртуальные методы того же класса", истинность высказывания не изменится. В любом случае программист должен следить, чтобы не было ошибочных обращений к неинициализированным переменным. Вызов именно виртуальных методов практически ничего к этой опасности не добавляет.


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

V>Наплодить ошибок можно в любой системе. А в вопросе речь шла о сравнительно простой логике, которой поля класса вообще не нужны.

V>Как жалко, что в C# нет модификатора параметров const как в C++
Что бы это изменило в данном аспекте? Как бы повлияло на инициализацию полей?

S>>О специфике виртуальных методов, вызываемых из конструктора базового класса, надо помнить не только при написании производных классов, а так же при рефакторинге. И если у меня в проекте 15Мб исходников, то мне помнить о таких дополнительных соглашениях некоторых классов довольно проблематично. А делать себе и коллегам пометки в коде "если обратишься к полю — ССЗБ" как-то несолидно.

V>Документировать нетривиальные места кода теперь стало несолидно? Я что-то упустил в этой жизни?
Предпочитаю не вносить нетривиальные места, чем их документировать.
Благо, альтернатива такому решению есть.
Re[7]: Задать значение поля базового класса. C#
От: vmpire Россия  
Дата: 04.03.09 11:38
Оценка:
Здравствуйте, samius, Вы писали:

V>>Наплодить ошибок можно в любой системе. А в вопросе речь шла о сравнительно простой логике, которой поля класса вообще не нужны.

V>>Как жалко, что в C# нет модификатора параметров const как в C++
S>Что бы это изменило в данном аспекте? Как бы повлияло на инициализацию полей?
Можно было бы хотя бы застраховаться от изменений полей класса такими методами.
Я согласен, что решение не очень изящное, но принципиальных причин не использовать его не вижу. В ряде случаев оно можжет упростить жизнь.
Re[8]: Задать значение поля базового класса. C#
От: samius Япония http://sams-tricks.blogspot.com
Дата: 04.03.09 12:06
Оценка:
Здравствуйте, vmpire, Вы писали:

V>Здравствуйте, samius, Вы писали:


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


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

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

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

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

Все это я предпочту вызовам виртуальных методов из конструктора базового класса. Однако допускаю ряд случаев, когда никакие другие решения не подойдут по каким-либо причинам. В таком случае придется использовать это решение. Табу на него у меня нет
Re[9]: Задать значение поля базового класса. C#
От: vmpire Россия  
Дата: 04.03.09 12:43
Оценка:
Здравствуйте, samius, Вы писали:

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


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


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


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


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


S>Все это я предпочту вызовам виртуальных методов из конструктора базового класса. Однако допускаю ряд случаев, когда никакие другие решения не подойдут по каким-либо причинам. В таком случае придется использовать это решение. Табу на него у меня нет


Всё это вопрос личных предпочтений и целесообразности, как мне кажется. Я совсем не утверждаю, что нужно дёргать виртуальные методы из конструктора в каждом втором классе. Мне это за всю жизнь понадобилось всего один раз, в других случаях удавалось сделать более красивое решение.
К сожалению, это было несколько лет назад, так что контекст я сейчас уже не вспомню.
В данном конкретном случае, с которого всё началось, я считаю наиболее подходящим решение rg45.
Re[10]: Задать значение поля базового класса. C#
От: samius Япония http://sams-tricks.blogspot.com
Дата: 04.03.09 12:57
Оценка:
Здравствуйте, vmpire, Вы писали:

V>Всё это вопрос личных предпочтений и целесообразности, как мне кажется.

Согласен
V>Я совсем не утверждаю, что нужно дёргать виртуальные методы из конструктора в каждом втором классе. Мне это за всю жизнь понадобилось всего один раз, в других случаях удавалось сделать более красивое решение.
V>К сожалению, это было несколько лет назад, так что контекст я сейчас уже не вспомню.
Да не надо.

V>В данном конкретном случае, с которого всё началось, я считаю наиболее подходящим решение rg45.

Я тоже.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.