有没有办法在所有构造函数运行后立即自动调用特定方法?

时间:2011-11-03 17:32:57

标签: c# constructor

我希望能够在构造派生对象时自动调用特定方法,但是我想不出怎么做。以下代码说明。另一个答案是OnLoad,但我在Mac上为Unity做这个,OnLoad似乎不支持我的平台。有什么建议吗?

public class Parent {

    public Parent ()
    {
        // A. Stuff to do before child constructor code runs
        DoThisAutomaticallyAfterConstruction();
    }

    public void DoThisAutomaticallyAfterConstruction()
    {
        // C. In this example, this will run after A, before B. I want it to run ABC
    }
}

public class Child : Parent {

    public Child () : base()
    {
        // B. Stuff to do here after parent constructor code runs
    }
}

4 个答案:

答案 0 :(得分:14)

不幸的是,没有内置的方法来做你想要的(这是一个经常被要求的功能)。

一种解决方法是实现工厂模式,您不通过直接调用构造函数来创建对象,而是实现静态方法来为您创建它们。例如:

public class MyClass
{
  public MyClass()
  {
    // Don't call virtual methods here!
  }

  public virtual void Initialize()
  {
    // Do stuff -- but may be overridden by derived classes!
  }
}

然后添加:

public static MyClass Create()
{
  var result = new MyClass();

  // Safe to call a virtual method here
  result.Initialize();

  // Now you can do any other post-constructor stuff

  return result;
}

而不是做

var test = new MyClass();

你可以做到

var test = MyClass.Create();

答案 1 :(得分:4)

这听起来像是工厂的好候选人。使所有构造函数成为私有或受保护的,要求代码的使用者在需要对象实例时调用工厂方法。在工厂方法中,使用new运算符创建对象,然后在返回对象之前调用DoThisAutomaticallyAfterConstruction()

修改

工厂可能是静态方法,或者您可能有工厂对象。例如,请参阅维基百科上http://en.wikipedia.org/wiki/Abstract_factory_pattern的抽象工厂模式,以及http://msdn.microsoft.com/en-us/library/wda6c36e.aspx上的ADO.NET DbProviderFactories的文档,以了解实际实现情况。

答案 2 :(得分:2)

根据您的示例,您正在完成 ACB ,您想要完成 ABC

为了在子构造函数之后运行代码,你需要在B(子构造函数)之后调用你不能在A(父构造函数)调用代码然后你不会完成ABC。

在子类构造函数的末尾移动DoThisAutomaticallyAfterConstruction()

但这确实是一个奇怪的问题。

答案 3 :(得分:1)

虽然@Jeremy Todd(已接受)的答案有效并且是一个被广泛接受的问题解决方案,但它有一个缺点:不是IoC和序列化友好,因为你的类无法使用new正确构建。让我介绍一下使用一些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时,这将禁止任何未从实际类中调用的调用。