c#对象构造后如何执行代码(postconstruction)
本文关键字:执行 代码 postconstruction 何执行 对象 | 更新日期: 2023-09-27 18:03:16
在下面的代码中可以看到,在构造Child对象期间,DoStuff()
方法在Init()
方法之前被调用。
我在一个情况下,我有许多子类。因此,在每个子类的构造函数中,直接在Init()
之后重复调用DoStuff()
方法并不是一个优雅的解决方案。
是否有任何方法可以在父类中创建某种post构造函数,该构造函数将在子构造函数之后执行?这样,我就可以调用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
}
}
如果你有一个复杂的逻辑来构造你的对象,那么考虑FactoryMethod模式。
在你的例子中,我将它实现为一个简单的
public static Parent Construct(someParam)
方法,该方法接受一些参数,并根据参数决定实例化哪个子类。您可以从构造函数中删除DoStuff()
方法调用,并在新实例的Construct()
中调用它。
同样,你应该避免在构造函数中调用虚/抽象方法。构造函数中的虚成员调用
让我介绍一个使用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
时,它将抑制任何不是从实际类发出的调用。
这个怎么样:
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
}
}
正如其他人提到的,您应该使用工厂模式。
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();
}
我强烈建议使用Factory作为模式。
如果可能的话:
1。将所有子类和抽象类推入单独的程序集。
2。像内部方法一样声明子函数的vector,这样程序集外的任何人都不能仅仅通过调用vector来构造它们。
3 。实现Factory类来构造调用者指定的对象类型,这显然会在实际创建对象之后强制调用抽象DoStuff()方法,但在将其返回给调用者之前。
的好处是:它还会给你额外的抽象层次,所以如果将来你需要更多的函数调用或任何其他类型的逻辑复杂性,你需要的只是把它们添加到你的工厂类中。
。
对
在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()
将在构造函数之后立即调用。
更正:根据这个答案,当基类的构造函数在子类的构造过程中被调用时,您无法确定
。这行不通:
public Child()
// DoStuff is called here after Init
// because of the overridden default constructor
{
Init();
base();
}
所以,是的,正如其他人所注意到的,如果事件顺序很重要,那么基类需要能够通过按顺序声明抽象方法来适应这一点,或者(更好的是)通过让子类的DoStuff实现表示事件顺序:
protected override void DoStuff()
{
Init();
base.DoStuff();
}
DoStuff是抽象的。从DoStuff的顶部调用Init
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>();
}
}
…
public MyClass()
{
Dispatcher.UIThread.Post(RunAfterConstructor);
}
我也尝试了Task.Run
,但没有可靠地工作。
与其使用abstract
方法(这需要在所有子类中实现该方法),不如尝试:
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
}