在 C# 中,在基构造函数之前执行派生构造函数

发布于 2024-07-16 15:10:39 字数 1071 浏览 11 评论 0原文

我的问题是,我想将一个对象传递给派生类,但它必须在基类构造函数之前完成,因为基类将立即调用派生类的 Start() 方法使用该对象。

以下是基类的摘录(从 BarcodeScanner 重命名为方便)。

public abstract class MyBase
{    
    public MyBase()
    {
        if (Initialize())
            this.Start();
    }

    public abstract bool Initialize();
    public abstract void Start();
}

这是我正在创建的派生类。

class MyDerived : MyBase
{
    private string sampleObject;

    public MyDerived (string initObject)
    {
        sampleObject = initObject;
    }

    public override bool Initialize() 
    { 
        return GetDevice();
    }
    public override void Start() 
    { 
        Console.WriteLine("Processing " + sampleObject.ToString()); 
    }
}

我怀疑你能否让 C# 在基本构造函数之前执行派生构造函数; 所以我实际上只是在寻找一种解决方案,在使用对象之前将对象传递给派生类。

我通过将 Initialize/Start if 块放入 MyDerived 构造函数中解决了这个问题。 然而,还有其他类从基类派生; 所以我最终不得不在每个派生类中重复这段初始化/启动代码。 我希望看到修改基类的替代方法。

My problem here is that I would like to pass an object to a derived class, but it must be done before the base class constructor, since the base class will immediately call the derived class's Start() method that uses the object.

Here's an excerpt from the base class, (renamed from BarcodeScanner for convenience).

public abstract class MyBase
{    
    public MyBase()
    {
        if (Initialize())
            this.Start();
    }

    public abstract bool Initialize();
    public abstract void Start();
}

Here's the derived class that I'm creating.

class MyDerived : MyBase
{
    private string sampleObject;

    public MyDerived (string initObject)
    {
        sampleObject = initObject;
    }

    public override bool Initialize() 
    { 
        return GetDevice();
    }
    public override void Start() 
    { 
        Console.WriteLine("Processing " + sampleObject.ToString()); 
    }
}

I doubt you can make C# execute a derived constructor before the base constructor; so I'm really just looking for a solution to pass an object to the derived class before the object is used.

I've gotten around this by putting the Initialize/Start if block inside the MyDerived constructor. However, there are other classes deriving from the base class; so I ended up having to repeat this block of Initialize/Start code in every derived class. I'd like to see an alternative to modifying the base class.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

可遇━不可求 2024-07-23 15:10:39

你想要做的事情在 C# 中是不可能的。 基类中的构造函数必须在任何派生类的构造函数之前运行,否则可能会损坏对象状态。 子对象必须能够假定其基础已完全构造且可用。

What you are trying to do is impossible in C#. A constructor in a base class must be run before the constructor of any derived class otherwise there would be potential for corrupt object state. A child object must be able to assume that its base is fully constructed and available.

野の 2024-07-23 15:10:39

恕我直言,你的设计是错误的。 您不应该从构造函数内部启动该过程。 您的使用代码应在需要时显式调用 Start() 方法。

IMHO your design is wrong. You shouldn't start the process from within the constructor. Your consuming code should explicitly call the Start() method when required.

栖竹 2024-07-23 15:10:39

我会重新设计您的设计,以便在构造后调用 Initialize (以及可能的 Start() - 尽管我通常将其作为用户调用的公共方法)。

如果您正在制作 BarcodeScanner,则可以在第一次扫描时执行此操作。 只需使用派生类中的数据延迟初始化您的成员即可。

这将解决您的问题,而用户的使用情况不会发生真正的变化。

I would rework your design so that Initialize (and potentially Start() - though I'd normally have this be a public method that's called by the user) are called after construction.

If you're making a BarcodeScanner, you could do this the first time you go to scan. Just lazy-initialize your members using the data from the derived class.

This will work around your issue, with no real change in usage from the user.

萌酱 2024-07-23 15:10:39

抱歉添加到旧线程,但也许有人对另一个答案感兴趣。 我找到了一种(IMO)巧妙的方法来处理逻辑,不仅仅是在涉及继承的类构造函数中分配字段here
如果您只想为这个特定的层次结构使用 if,而不使用具有接口和扩展方法的通用解决方案,您可以在一个类树中使用相同的概念,如下所示:

public abstract class MyBase
{    
    protected MyBase()
    {
        Initialize(this) // just to illustrate this will never do anything as MyBase can never be the run time type.
    }

    protected bool IsInitialized { get; private set; } = false;

    protected static bool Initialize<T>(T instance) where T: MyBase
    {
        if (instance?.GetType() == typeof(T)) // check if this is called from the constructor of instance run time type
            return instance.IsInitialized || ( instance.IsInitialized = instance.Initialize() );
        return false;
    }

    protected abstract bool Initialize();
    public abstract void Start();
}

并派生:

class MyDerived : MyBase
{
    private string sampleObject;
    protected bool started = false;

    public MyDerived (string initObject)
    {
        sampleObject = initObject;
        if (Initialize(this)) // if this is the most derived constructor, this will run Initialize() and return whether it was successful
            this.Start();// EDIT: Just to illustrate. Normally constructors should only initialize an instance and not perform operations on it (as mentioned in other answers).
    }

    protected override bool Initialize() 
    { 
       return GetDevice();
    }

    public override void Start() 
    { 
        // if Start() would be protected, we don't need the IsInitialized property and we can move this check to the constructor on the returned value of the Initialize<T>() call.
        if (!IsInitialized) throw new InvalidOperationException("Initialization failed.");
        // if you want to have this method exposed public, we need to check if this instance is successfully initialized from the constructor and not in started state already.
        if (started) return;

        Console.WriteLine("Processing " + sampleObject.ToString()); 
        started = true;
        if (!Run(sampleObject)) started = false;
    }
}

Sorry for adding to an old thread, but maybe someone is interested in another answer. I found an (IMO) neat way to handle logic doing something more than (and after) just assigning fields in class constructors where inheritance is involved here.
If you just want to have if for this specific hierarchy and not use the generic solution with an interface and an extension method, you could use the same concept in one class tree like this:

public abstract class MyBase
{    
    protected MyBase()
    {
        Initialize(this) // just to illustrate this will never do anything as MyBase can never be the run time type.
    }

    protected bool IsInitialized { get; private set; } = false;

    protected static bool Initialize<T>(T instance) where T: MyBase
    {
        if (instance?.GetType() == typeof(T)) // check if this is called from the constructor of instance run time type
            return instance.IsInitialized || ( instance.IsInitialized = instance.Initialize() );
        return false;
    }

    protected abstract bool Initialize();
    public abstract void Start();
}

and derived:

class MyDerived : MyBase
{
    private string sampleObject;
    protected bool started = false;

    public MyDerived (string initObject)
    {
        sampleObject = initObject;
        if (Initialize(this)) // if this is the most derived constructor, this will run Initialize() and return whether it was successful
            this.Start();// EDIT: Just to illustrate. Normally constructors should only initialize an instance and not perform operations on it (as mentioned in other answers).
    }

    protected override bool Initialize() 
    { 
       return GetDevice();
    }

    public override void Start() 
    { 
        // if Start() would be protected, we don't need the IsInitialized property and we can move this check to the constructor on the returned value of the Initialize<T>() call.
        if (!IsInitialized) throw new InvalidOperationException("Initialization failed.");
        // if you want to have this method exposed public, we need to check if this instance is successfully initialized from the constructor and not in started state already.
        if (started) return;

        Console.WriteLine("Processing " + sampleObject.ToString()); 
        started = true;
        if (!Run(sampleObject)) started = false;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文