反射:在基类中调用派生属性getter

问题描述 投票:1回答:1

在将代码集成到更大的系统中时,我遇到了一些代码约定问题。在以下示例中,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

(更具体地说,BaseClass是MVVM的INotifyPropertyChanged实现,它希望为其通知属性进行一些自动连接。)

问题是,这里的做法有什么不好? 1)通过基类中的反射调用派生类成员,或2)属性getter和方法依赖于已经调用了它们的类构造函数的假设?我应该在我的所有属性中添加空检查和类似逻辑,还是应该禁用此基类行为(如果我不打算在我的代码中的任何地方使用PropertyEnvelop)?我有一种强烈的感觉,尝试调用尚未完全实例化的实例的属性的getters是错误的(正如所提到的博客的second part所说的那样),但有没有任何官方指导方针推荐一个选项而不是另一个? (我们有复杂的ViewModel类,在ctors期间有很多内部逻辑运行。)

对我来说幸运的是,真正的BaseClass有一个标志来禁用这种行为,但是它实现为虚拟bool属性,而继承的类只是覆盖它;所以,BaseClass也在其构造函数中调用其虚拟成员,其中(AFAIK)也是一个糟糕的代码实践。

c# mvvm reflection conventions
1个回答
0
投票

我的公司最终决定他们的原始模式是错误的,他们将改变基类实现。建议是:

1)如果你用一些[WarningAlertThisWillBeInvokedBeforeYourCtorAttribute]标记你想在基础构造函数中自动挂钩的所有属性,那么你至少会在一个地方得到getter和警告。在Reflection中,您可以先检查属性,然后再调用getter。

2)如果你不想引入属性(在这种情况下,引入自动钩子以尽可能地加强开发),你至少可以在调用getter之前检查属性的类型。然后你可以把警告放入类型摘要中,比如

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

3)通常,在基类ctor中调用属性getter并不是一个好主意,所以我们将寻求另一种解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.