简体   繁体   English

反思:在基类中调用派生的属性获取器

[英]Reflection: Invoking derived property getters in base class

I ran into some code convention issues during integration of my code into a larger system. 在将代码集成到更大的系统期间,我遇到了一些代码约定问题。 In the following example, BaseClass and DerivedClass1 are the previously existing large system, and DerivedClass2 is my code which was inherited from another base class before the merge. 在下面的示例中,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
    }
}

Link 链接

(To be more specific, BaseClass is implementation of INotifyPropertyChanged for MVVM and it wants to do some auto-hookup for its notification properties.) (更具体地说,BaseClass是MVVM的INotifyPropertyChanged的实现,它想对其通知属性进行一些自动连接。)

The question is, what practice here is bad? 问题是,这里的哪种做法不好? 1) Invoking derived class members via reflection in the base class, or 2) property getters and methods relying on the assumption that their class' constructor has been invoked already? 1)通过在基类中的反映来调用派生类成员,或2)属性获取器和方法依赖于其类的构造函数已经被调用的假设? Should I add null-checks and similar logic into all my properties, or should I disable this base class behavior (if I'm anyway not going to use PropertyEnvelop anywhere in my code)? 我应该在所有属性中添加空检查和类似的逻辑,还是应该禁用此基类行为(如果我无论如何都不打算在代码中的任何地方使用PropertyEnvelop)? I have a strong feeling that it is wrong to try invoking getters of properties of an instance which is not fully instantiated yet (as the second part of the mentioned blog says), but are there any official guidelines which recommend one option over another? 我有一种强烈的感觉,尝试调用尚未完全实例化的实例的属性的吸气剂是错误的(正如所提到的博客的第二部分所述),但是是否有任何官方指南推荐一个选项而不是另一个选项? (We have complex ViewModel classes with lots of internal logic to run during ctors.) (我们有复杂的ViewModel类,在ctor期间要运行许多内部逻辑。)

Fortunately for me, the real BaseClass has a flag to disable this behavior, but it is implemented as virtual bool property, and inherited classes just override it; 对我来说幸运的是,真正的BaseClass有一个禁用此行为的标志,但它是作为虚拟bool属性实现的,而继承的类只是重写它; so, BaseClass also calls its virtual members in its constructor, which (AFAIK) is also a bad code practice. 因此,BaseClass还会在其构造函数中调用其虚拟成员,这(AFAIK)也是一种不好的代码习惯。

My company finally decided that their original pattern was wrong, and they will change the base class implementation. 我的公司最终认为他们的原始模式是错误的,他们将更改基类的实现。 The suggestions are: 建议是:

1) if you mark all properties you want to auto-hook in base constructor with some [WarningAlertThisWillBeInvokedBeforeYourCtorAttribute], then you'll at least have the getter and the warning in one place. 1)如果使用[WarningAlertThisWillBeInvokedBeforeYourCtorAttribute]标记要在基本构造函数中自动挂接的所有属性,则至少将getter和警告放在一个位置。 In Reflection, you can first check the attributes and only after that invoke the getter. 在Reflection中,您只能先检查属性,然后再调用getter。

2) If you don't want to introduce attributes (as in this case, where the auto-hook was introduced to fasten development as much as possible), you can at least check the type of the property before invoking the getter. 2)如果您不想引入属性(例如,在这种情况下,引入了自动挂钩以尽可能加快开发速度),则可以至少在调用getter之前检查属性的类型 And then you can put the warning into the type summary, like 然后可以将警告放入类型摘要中,例如

/// <summary>
/// WARNING! Property of this type should be initialized inline, not in ctor!
/// </summary>
public class PropertyEnvelop
{
    (...)
}

3) generally, it is not a good idea to invoke the property getter in base class ctor at all, so we'll seek for another solution. 3)通常,根本不要在基类ctor中调用属性getter,因此,我们将寻求另一种解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM