C# 如何在对象构造后执行代码(postconstruction)

发布于 2024-11-25 20:54:02 字数 768 浏览 0 评论 0原文

正如您在下面的代码中看到的,在构建 Child 对象期间,DoStuff() 方法在 Init() 方法之前被调用。

我现在的情况是,我有很多儿童班。因此,在每个子级构造函数中的 Init() 之后直接重复调用 DoStuff() 方法并不是一个优雅的解决方案。

有什么方法可以在父类中创建某种后置构造函数,该构造函数将在子构造函数之后执行?这样,我就可以调用其中的 DoStuff() 方法。

如果您有任何其他设计想法可以解决我的问题,我也想听听!

abstract class Parent
{
    public Parent()
    {
        DoStuff();
    }

    protected abstract void DoStuff();
}

class Child : Parent
{
    public Child()
    // DoStuff is called here before Init
    // because of the preconstruction
    {
        Init();
    }

    private void Init()
    {
        // needs to be called before doing stuff
    }

    protected override void DoStuff() 
    {
        // stuff
    }
}

As you can see in the code below, the DoStuff() method is getting called before the Init() one during the construction of a Child object.

I'm in a situation where I have numerous child classes. Therefore, repeating a call to the DoStuff() method directly after Init() in the constructor of each child wouldn't be an elegant solution.

Is there any way I could create some kind of post constructor in the parent class that would be executed after the child's constructor? This way, I could call to the DoStuff() method there.

If you have any other design idea which could solve my problem, I'd like to hear it too!

abstract class Parent
{
    public Parent()
    {
        DoStuff();
    }

    protected abstract void DoStuff();
}

class Child : Parent
{
    public Child()
    // DoStuff is called here before Init
    // because of the preconstruction
    {
        Init();
    }

    private void Init()
    {
        // needs to be called before doing stuff
    }

    protected override void DoStuff() 
    {
        // stuff
    }
}

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

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

发布评论

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

评论(11

美煞众生 2024-12-02 20:54:02

如果您有复杂的逻辑来构建对象,请考虑 FactoryMethod 模式。

在您的情况下,我会将其实现为一个简单的

public static Parent Construct(someParam)

方法,该方法接受一些参数,并根据它决定要实例化哪个子类。
您可以从构造函数中删除 DoStuff() 方法调用,并在新实例的 Construct() 内部调用它。

另外,您应该避免在构造函数中调用虚拟/抽象方法。有关更多详细信息,请参阅此问题:构造函数中的虚拟成员调用

If you have a complex logic for constructing your objects then consider FactoryMethod pattern.

In your case I would implement it as a simple

public static Parent Construct(someParam)

method that takes some parameter and based on it decides which child class to instantiate.
You can remove your DoStuff() method call from the constructor and call it inside Construct() on the new instance.

Also, you should avoid virtual/abstract method calls in the constructors. See this question for more details: Virtual member call in a constructor

白云不回头 2024-12-02 20:54:02

让我介绍一个使用一些 C# 功能的通用解决方案。请注意,此解决方案不需要您使用工厂模式或在构造对象后调用任何内容,并且它适用于任何类,只需使用单个方法实现接口即可。
首先,我们声明一个我们的类必须实现的接口:

public interface IInitialize {
    void OnInitialize();
}

接下来,我们为此接口添加一个静态扩展类,并添加 Initialize 方法:

public static class InitializeExtensions
{
    public static void Initialize<T>(this T obj) where T: IInitialize
    {
        if (obj.GetType() == typeof(T))    
            obj.OnInitialize();
    }
}

现在,如果我们需要一个类及其所有后代在该对象之后调用初始化器完全构造完毕后,我们需要做的就是实现 IInitialize 并在构造函数中添加一行:

public class Parent : IInitialize
{
    public virtual void OnInitialize()
    {
        Console.WriteLine("Parent");
    }

    public Parent()
    {
        this.Initialize();
    }
}

public class Child : Parent
{
    public Child()
    {
        this.Initialize();
    }

    public override void OnInitialize()
    {
        Console.WriteLine("Child");
    }
}

public class GrandChild : Child
{
    public GrandChild()
    {
        this.Initialize();
    }

    public override void OnInitialize()
    {
        Console.WriteLine("GrandChild");
    }
}

技巧是,当派生类调用扩展方法 Initialize 时,将会抑制任何不是从实际类发出的调用。

Let me introduce a general solution using some C# features. Note that this solution does not require you to use a factory pattern or invoke anything after constructing the object, and it works on any class with just implementing an interface with a single method.
First we declare an interface that our classes will have to implement:

public interface IInitialize {
    void OnInitialize();
}

Next we add a static extension class for this interface, and add the Initialize method:

public static class InitializeExtensions
{
    public static void Initialize<T>(this T obj) where T: IInitialize
    {
        if (obj.GetType() == typeof(T))    
            obj.OnInitialize();
    }
}

Now, if we need a class and all of its descendants to call an initializer right after the object is fully constructed, all we need to do is implement IInitialize and append a line in the constructor:

public class Parent : IInitialize
{
    public virtual void OnInitialize()
    {
        Console.WriteLine("Parent");
    }

    public Parent()
    {
        this.Initialize();
    }
}

public class Child : Parent
{
    public Child()
    {
        this.Initialize();
    }

    public override void OnInitialize()
    {
        Console.WriteLine("Child");
    }
}

public class GrandChild : Child
{
    public GrandChild()
    {
        this.Initialize();
    }

    public override void OnInitialize()
    {
        Console.WriteLine("GrandChild");
    }
}

The trick is that when a derived class calls the extension method Initialize, that will suppress any calls not made from the actual class.

离笑几人歌 2024-12-02 20:54:02

这个怎么样:

abstract class Parent
{
    public Parent()
    {
        Init();
        DoStuff();
    }

    protected abstract void DoStuff();
    protected abstract void Init();
}

class Child : Parent
{
    public Child()
    {
    }

    protected override void Init()
    {
        // needs to be called before doing stuff
    }

    protected override void DoStuff() 
    {
        // stuff
    }
}

How about this:

abstract class Parent
{
    public Parent()
    {
        Init();
        DoStuff();
    }

    protected abstract void DoStuff();
    protected abstract void Init();
}

class Child : Parent
{
    public Child()
    {
    }

    protected override void Init()
    {
        // needs to be called before doing stuff
    }

    protected override void DoStuff() 
    {
        // stuff
    }
}
爱要勇敢去追 2024-12-02 20:54:02

正如其他人提到的,您应该使用工厂模式。

public class Parent
{
    public Parent()
    {            
    }

    public virtual void PostConstructor()
    {
    }
}

public class Child : Parent
{
    public override void PostConstructor()
    {
        base.PostConstructor();

        // Your code here
    }
}

public void FactoryMethod<T>() where T : Parent
{
    T newobject = new T();
    newobject.PostConstructor();
}

As others have mentioned, you should use a Factory Pattern.

public class Parent
{
    public Parent()
    {            
    }

    public virtual void PostConstructor()
    {
    }
}

public class Child : Parent
{
    public override void PostConstructor()
    {
        base.PostConstructor();

        // Your code here
    }
}

public void FactoryMethod<T>() where T : Parent
{
    T newobject = new T();
    newobject.PostConstructor();
}
烟凡古楼 2024-12-02 20:54:02

我强烈建议使用 Factory 像模式一样。

如果可能的话:

1。将所有子类和抽象类推入单独的程序集中。

2。像内部方法一样声明子对象的 ctor,因此该程序集中没有人可以仅通过调用 ctor 来构造它们。

3。实现 Factory 类来构造调用者指定的对象类型,这显然会在实际创建对象之后、将其返回给调用者之前强制调用抽象 DoStuff() 方法。

好处是:它还会为您提供额外的抽象级别,因此,如果将来您需要更多的函数调用或任何其他类型的逻辑复杂性,您将需要的是只需将它们添加到您的 Factory 类中即可。

那是。

问候

I would strongly suggest use Factory like a pattern.

If it's possible:

1. Push all your childs and abstract class into separate assembly.

2. Declare ctors of childs like internal methods, so no one out of that assembly is can construct them just by calling ctor.

3. Implement the Factory class to construct for caller specified objects type, which obviuoly will forse calling of abstract DoStuff() method after actual creation of anobject, but before returning it to caller.

Good thing about this is that: It will give you also additional level of abstraction, so if in the future you will need some more functions call or any other type of logical complexity, what you will need, is just add them into your Factory class.

That is.

Regards

胡渣熟男 2024-12-02 20:54:02

在 WPF 应用程序中,您可以在 Dispatcher 的帮助下推迟 DoStuff() 的调用:

abstract class Parent
{
    public Parent()
    {
        Dispatcher.CurrentDispatcher.BeginInvoke(new Action(this.DoStuff));
    }

    private void DoStuff()
    {
        // stuff, could also be abstract or virtual
    }
}

但是,不保证 DoStuff()将在构造函数之后立即调用。

In WPF applications, you can postpone the invokation of DoStuff() with the help of Dispatcher:

abstract class Parent
{
    public Parent()
    {
        Dispatcher.CurrentDispatcher.BeginInvoke(new Action(this.DoStuff));
    }

    private void DoStuff()
    {
        // stuff, could also be abstract or virtual
    }
}

However, it is not guaranteed that DoStuff() will be called immediately after the constructor.

り繁华旳梦境 2024-12-02 20:54:02

更正:根据此答案,您无法确定在子类构造期间何时调用基类的构造函数。

例如,这不起作用:

public Child()
// DoStuff is called here after Init
// because of the overridden default constructor
{
    Init();
    base();
} 

所以,是的,正如其他人所指出的,如果事件的顺序很重要,那么基类需要能够通过按顺序声明抽象方法来适应这一点,或者(更好)通过让子类的DoStuff 的实现代表事件的顺序:

protected override void DoStuff()
{
    Init();
    base.DoStuff();
}

Correction: As per this answer, you can't determine when the base class's constructor is invoked during construction of the subclass.

E.g. This doesn't work:

public Child()
// DoStuff is called here after Init
// because of the overridden default constructor
{
    Init();
    base();
} 

So, yes, as others have noted, if sequence of events matters, then the base class needs to be able to accommodate that by declaring abstract methods in order, or (better yet) by having the child class's implementation of DoStuff represent the sequence of events:

protected override void DoStuff()
{
    Init();
    base.DoStuff();
}
无人问我粥可暖 2024-12-02 20:54:02

DoStuff 是抽象的。只需从 DoStuff 顶部调用 Init 即可。

DoStuff is abstract. Just call Init from the top of DoStuff.

别靠近我心 2024-12-02 20:54:02
    class MyBase
    {
        public MyBase()
        {
            //... do something

            // finally call post constructor                
            PostConstructor<MyBase>();
        }

        public void PostConstructor<T>(  )
        {
            // check
            if (GetType() != typeof(T))
                return;

            // info
            System.Diagnostics.Debug.WriteLine("Post constructor : " + GetType());
        }
    }

    class MyChild : MyBase
    {
        public MyChild()
        {
            // ... do something

            // ... call post constructor
            PostConstructor<MyChild>();
        }
    }
    class MyBase
    {
        public MyBase()
        {
            //... do something

            // finally call post constructor                
            PostConstructor<MyBase>();
        }

        public void PostConstructor<T>(  )
        {
            // check
            if (GetType() != typeof(T))
                return;

            // info
            System.Diagnostics.Debug.WriteLine("Post constructor : " + GetType());
        }
    }

    class MyChild : MyBase
    {
        public MyChild()
        {
            // ... do something

            // ... call post constructor
            PostConstructor<MyChild>();
        }
    }
娇柔作态 2024-12-02 20:54:02

怎么样...

public MyClass()
{
    Dispatcher.UIThread.Post(RunAfterConstructor);
}

我也尝试过使用 Task.Run 但它工作不可靠。

How about...

public MyClass()
{
    Dispatcher.UIThread.Post(RunAfterConstructor);
}

I also tried with Task.Run but that didn't work reliably.

故事和酒 2024-12-02 20:54:02

您可以尝试:

public class Parent
{
    public Parent()
    {
        PostConstructor();
    }


    protected virtual void PostConstructor()
    {
    }
}

public class Child : Parent
{
    protected override void PostConstructor()
    {
        base.PostConstructor();

        /// do whatever initialization here that you require
    }
}

public class ChildWithoutOverride
{
    /// not necessary to override PostConstructor 
}

Rather than using an abstract method, which would require you to implement the method in all descendant classes, you might try:

public class Parent
{
    public Parent()
    {
        PostConstructor();
    }


    protected virtual void PostConstructor()
    {
    }
}

public class Child : Parent
{
    protected override void PostConstructor()
    {
        base.PostConstructor();

        /// do whatever initialization here that you require
    }
}

public class ChildWithoutOverride
{
    /// not necessary to override PostConstructor 
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文