解决构造函数中的虚拟成员调用

问题描述 投票:0回答:5

我有一个抽象类:

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
    }
}

还有一个派生类:

public class Example : ExampleBase
{
    public Example()
    {
    }

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

在基类中,ReSharper 告诉我

构造函数中的虚拟成员调用

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

上下文:我想在每个派生类中设置数据,然后在基类中处理这些数据。我想在基类中调用

SetupData()
方法,因为它在每个派生类中都是相同的。

派生类:

  • 设置数据

基类:

  • 处理数据
c# .net oop resharper
5个回答
17
投票

你不知道。您接受这样的事实:这是危险的,并且(尝试)阻止这种情况发生。这是设计缺陷!

您可以通过将调用移至最高级别的类来防止这种情况,或者让每个类对其自己负责,从而消除方法调用的不安全部分。那么你不需要另一个类(基类)来负责它的派生类。

如果那不可能。使用注释或任何其他可用的方法明确说明开发人员在更新代码时应考虑此问题。


0
投票

现在可以选择用

Action
(或
Func 
)参数替换抽象方法。

例如

public abstract class ExampleBase : IExampleBase
{
    protected ExampleBase(Action setupData) // new: Action parameter
    {
        setupData(); // new: call action instead of virtual method
    }

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

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

还有一个派生类:

public class Example : ExampleBase
{
    public Example(): base(SetupData) // new: Send SetupData methode
    {
    }

    private static void SetupData() // new: static and private
    {
        this.RelevantData = new Dictionary<int, Adress>
        { 1, new Adress { ... } },
        { 2, new Adress { ... } }
    }
}


-1
投票

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

问题在于,SetupData 可以访问由示例构造函数初始化的内容。但仅在ExampleBase 构造函数完成后才会调用Example 构造函数。


-1
投票

首先调用您的基类构造函数。如果子类中的重写方法取决于其构造函数中所做的任何操作,则它将不起作用。就我个人而言,我会寻找不同的设计,也许将抽象类传递到派生类中,而不是使用继承。


-1
投票

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

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();
    }
} 
© www.soinside.com 2019 - 2024. All rights reserved.