关于c#:在构造函数中解决虚拟成员调用

Solving virtual member call in constructor

我有一个抽象类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class ExampleBase : IExampleBase
{
    protected ExampleBase()
    {
        this.SetupData();
    }

    protected abstract Dictionary<int, Adress> RelevantData { get; set; }

    protected abstract void SetupData();

    public void ProcessData()
    {
        // use RelevantData
    }
}

以及派生类:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Example : ExampleBase
{
    public Example()
    {
    }

    protected override void SetupData()
    {
        this.RelevantData = new Dictionary<int, Adress>
        { 1, new Adress { ... } },
        { 2, new Adress { ... } }
    }
}

在基类中,Resharper告诉我

Virtual member call in constructor

我知道,由于执行顺序的原因调用该方法是危险的。但我该如何解决这个问题呢?

上下文:我想在每个派生类中设置数据,然后在基类中处理这些数据。我想在基类中调用SetupData()方法,因为它在每个派生类中都是相同的。

派生类:

  • 建立数据

基类:

  • 处理数据


你没有。你接受这是危险的事实,并且(试着)阻止它。这是一个设计缺陷!

例如,您可以通过将调用移动到最高级别的类来防止这种情况发生,或者使每个类都对其负责,从而删除方法调用的不安全部分。那么您不需要另一个类(基类)来负责它的派生类。

如果不可能的话。在更新代码时,使用注释或任何其他可用的方法来非常清楚地说明开发人员应该考虑到这个问题。


所以每个派生类中都有几行代码如果您需要控制流程顺序,那么您可以这样做

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
public abstract class MyBase
{
    public void ProcessData()
    {
        bool processData = true;
    }
    public MyBase()
    {
        bool myBase = true;
    }
    public MyBase(int pass)
    {
        bool myBase = true;
    }
}
public class Example : MyBase
{
    public void GetData() {}
    public Example()
        : base(1)
    {
        bool example = true;
        GetData();
        ProcessData();
    }
}


首先调用基类构造函数。如果子类中的重写方法依赖于其构造函数中所做的任何操作,则它将无法工作。我个人会寻找一种不同的设计,可能将抽象类传递到派生类中,而不是使用继承。


在示例(以及其他派生类)的构造函数(而不是ExampleBase)中调用SetupData,并使示例成为密封类。

问题是,SetupData可以访问一些将由示例构造函数初始化的内容。但只有在ExampleBase构造函数完成后才调用示例构造函数。