Я столкнулся с некоторыми проблемами при кодировании во время интеграции моего кода в большую систему. В следующем примере BaseClass и DerivedClass1 представляют собой ранее существующую большую систему, а DerivedClass2 - это мой код, который был унаследован от другого базового класса до слияния.
public abstract class BaseClass
{
protected BaseClass()
{
foreach (var property in this.GetType().GetProperties())
{
var value = property.GetValue(this);
if (value is PropertyEnvelop)
{
(...)
}
}
}
}
public class DerivedClass1 : BaseClass
{
public PropertyEnvelop MyProperty { get; }
= new PropertyEnvelop("MyPropertyName", typeof(int), default(int));
// this is fine, because property initializers run in reverse order:
// 1. Derived class property initializers
// 2. Base class property initializers
// 3. Base class constructor
// 4. Derived class constructor
// see link
}
public class DerivedClass2 : BaseClass
{
public ComplexItem Item
{ get { return ComputeComplexItem(SimpleItem1, SimpleItem2); } }
// this is BROKEN, because stuff like SimpleItem1, SimpleItem2
// and ComputeComplexItem TOTALLY depend on some logic from
// DerivedClass2 constructor and produce exceptions if the ctor
// wasn't invoked yet.
public DerivedClass2()
{
// prepare everything to bring DerivedClass2 in a valid state
}
}
Ссылка
(Точнее говоря, BaseClass является реализацией INotifyPropertyChanged для MVVM, и он хочет выполнить некоторую автоподключение для своих свойств уведомлений.)
Вопрос в том, какая практика здесь плохая? 1) Вызов членов производного класса через отражение в базовом классе, или 2) Получатели свойств и методы, основанные на предположении, что конструктор их класса уже был вызван? Должен ли я добавить нулевые проверки и аналогичную логику во все мои свойства или я должен отключить это поведение базового класса (если я в любом случае не собираюсь использовать PropertyEnvelop где-нибудь в моем коде)? У меня есть сильное чувство, что неправильно пытаться вызывать методы получения свойств экземпляра, который еще не полностью создан (как говорится в второй части упомянутого блога), но есть ли официальные рекомендации, которые рекомендуют один вариант над другим? (У нас есть сложные классы ViewModel с большим количеством внутренней логики для выполнения во время ctors.)
К счастью для меня, настоящий BaseClass имеет флаг для отключения этого поведения, но он реализован как свойство виртуального bool, а унаследованные классы просто переопределяют его; поэтому BaseClass также вызывает своих виртуальных членов в своем конструкторе, что (AFAIK) также является плохой практикой кода.