2010-04-30 18 views
7

Có cách nào để thực hiện việc này trong C# không? Tôi biết rằng lớp con sẽ gọi hàm tạo của lớp bậc trên trước khi gọi hàm tạo riêng của nó, nhưng nếu tôi có một số mã trên lớp cha mà chỉ nên được thực thi sau khi tất cả các hàm tạo lớp con đã được gọi?Làm cách nào để thực thi một số mã trong một siêu lớp sau khi tất cả các lớp con đã được xây dựng?

+3

Bạn có ví dụ sử dụng cụ thể không? –

Trả lời

3

Một cách để đạt được điều này sẽ là để đi cho một cấu trúc 2 giai đoạn và khởi tạo. Vì vậy, bạn xây dựng các trường hợp và sau đó gọi một phương thức khởi mà gọi các lớp cơ sở Initialize theo thứ tự thích hợp

class MyBase 
{ 
    // Only if need to do some core initialization 
    public MyBase() 
    { 
    } 

    public virtual Initialize() 
    { 
    // do some initialization stuff here 
    } 
} 

class MyDerived : MyBase 
{ 
    // Only if need to do some core initialization 
    public MyDerived() 
    { 
    } 

    public override Initialize() 
    { 
    // do some initialization stuff here 

    // Call the base class initialization function 
    base.Initialize(); 
    } 
} 
+3

Nếu bạn thực hiện tạo/khởi tạo hai lần, tôi sẽ tư vấn bằng cách sử dụng một phương pháp nhà máy hoặc nhà máy Asbtract để đảm bảo rằng ngữ nghĩa khởi tạo không được lan truyền trên tất cả các mã – LBushkin

+0

Ok, đó không phải là chính xác những gì tôi có nghĩa là nhưng nó kinda giúp tôi giải quyết vấn đề, ty –

0
class A : B 
{ 
    public A() : base() 
    { 
     base.doSomething(); 
    } 
} 

class B : C 
{ 
    public B() : base() 
    { 

    } 

    public void doSomething() { /* ... */ } 
} 

class C 
{ 
    public C() { /* ... */ } 
} 

Thực hiện theo thứ tự nên là:

  1. C :: ctor()
  2. B :: ctor()
  3. A :: ctor()
  4. B :: doSomething ()
+0

Như tôi đã nói, phương thức nên được thực hiện trong lớp cha, không phải trong lớp con, bạn chỉ cần gọi phương thức superclass trong lớp con. –

+0

Tôi nghi ngờ OP đang tìm kiếm giải pháp trong đó lớp cơ sở có thể đảm bảo rằng một số khởi chạy chạy sau khi loại được khởi tạo đầy đủ. Nếu không, mỗi tác giả lớp dẫn xuất phải đảm bảo gọi logic khởi tạo cần thiết. – LBushkin

+0

Thats chính xác những gì tôi cần: ( –

0

Tôi không chắc chắn ý của bạn là gì - bạn không thể gọi mã trong lớp siêu ở cuối lớp con cuối cùng của chúng tôi structor? Hoặc bạn có thể gọi nó trực tiếp sau khi instantiation.

class Program 
    { 
     static void Main(string[] args) 
     { 
      SubSub obj = new SubSub();     
      //obj.DoStuff(); 
      Console.ReadLine(); 
     } 
    } 

    class Super 
    { 
     public Super() 
     { 
      Console.WriteLine("Constructing Super"); 
     } 
     public void DoStuff() 
     { 
      Console.WriteLine("Doin' stuff"); 
     } 
    } 

    class Sub : Super 
    { 
     public Sub() 
     { 
      Console.WriteLine("Constructing Sub"); 
     } 
    } 

    class SubSub : Sub 
    { 
     public SubSub() 
     { 
      Console.WriteLine("Constructing SubSub"); 
      DoStuff(); 
     } 
    } 

Sản lượng này sẽ:

Constructing Super 
Constructing Sub 
Constructing SubSub 
Doin' stuff 
+0

Điều tôi ngụ ý là mã có thể được thực thi sau khi hoàn thành việc xây dựng đối tượng trong lớp cha, lớp con không nên biết về nó. –

3

Bạn có thể làm những điều sau đây, nhưng nó là rủi ro (xem Chỉnh sửa của tôi dưới đây):

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

    protected virtual void Initialize() 
    { 
     // do stuff 
    } 
} 

public class Child : Parent 
{ 
    protected override void Initialize() 
    { 
     // do child stuff 
     base.Initialize(); 
    } 
} 

Sửa

Như đã đề cập trong bình luận của Terrence của bên dưới, đây là một cách tiếp cận rủi ro vì Initialize() sẽ được thực hiện trước khi Child của constructor được thực thi. Nếu có bất kỳ trường nào được khởi tạo trong hàm tạo của Child, chúng sẽ không sẵn sàng nếu chúng được sử dụng bởi Initialize(). Điều này có thể gây ra các lỗi gây nhầm lẫn.

Một giải pháp đơn giản là từ bỏ yêu cầu của Phụ huynh Initialize() và thay vào đó có các lớp con gọi Initialize(). Như những người khác đã đề xuất, một tùy chọn khác sẽ là sử dụng mẫu nhà máy trừu tượng.

Đây là một giải pháp đơn giản có sử dụng một phương pháp nhà máy tĩnh:

class Program 
{ 
    static void Main() 
    { 
     Child.Create(() => new Child(5)); 
     Console.ReadKey(); 
    } 
} 

public abstract class Parent 
{ 
    protected virtual void Initialize() 
    { 
     Console.Write(" is the number."); 
    } 

    public static TChild Create<TChild>(Func<TChild> childGetter) 
     where TChild : Parent 
    { 
     var child = childGetter(); 
     child.Initialize(); 
     return child; 
    } 
} 

public class Child : Parent 
{ 
    private int _number; 

    public Child(int number) 
    { 
     _number = number; 
    } 

    protected override void Initialize() 
    { 
     Console.Write(_number.ToString()); 
     base.Initialize(); 
    } 
} 
+0

Điều này vi phạm các khuyến nghị chống gọi điện thoại ảo Phương pháp này có thể dẫn đến khó theo dõi lỗi. Xem: http://blogs.msdn.com/b/scottwil/archive/2005/01/14/353177.aspx và http : //stackoverflow.com/questions/308061/virtual ization-in-super-class-constructor – Terrence

+0

@Terrence, cảm ơn nhận xét của bạn. Đã cập nhật câu trả lời của tôi. – devuxer

2

Không có gì được xây dựng vào ngôn ngữ C# cho phép bạn làm điều này là. Tuy nhiên, bằng cách sử dụng một mô hình sáng tạo có thể hỗ trợ nó. Ví dụ: mẫu Abstract Factory có thể hữu ích ở đây. Nhà máy cơ sở sẽ đảm bảo rằng một phương thức được gọi trên lớp cơ sở mới được tạo ra khi nó được khởi tạo như là kiểu con cụ thể.

+0

Bạn có biết nếu Castle Windsor có thứ như thế không? –

+0

Đây thực sự là tên miền của một công cụ AOP như PostSharp (mà bây giờ bạn đã nhắc nhở tôi nên được đưa vào câu trả lời của tôi), nhưng có thể có Windsor làm điều đó. Chưa bao giờ thử. – RationalGeek

Các vấn đề liên quan