2008-09-26 18 views

Trả lời

92

Các nhà xây dựng cơ sở sẽ được gọi đầu tiên.

thử nó:

public class MyBase 
{ 
    public MyBase() 
    { 
    Console.WriteLine("MyBase"); 
    } 
} 

public class MyDerived : MyBase 
{ 
    public MyDerived():base() 
    { 
    Console.WriteLine("MyDerived"); 
    } 
} 
+1

Bạn nói đúng. Nhưng việc thực thi bắt đầu từ hàm khởi tạo có nguồn gốc, điều đầu tiên mà hàm tạo có nguồn gốc thực hiện là gọi hàm tạo cơ sở (nếu có). Vì vậy, nó xuất hiện như thể các nhà xây dựng cơ sở đang được gọi là đầu tiên. –

3

Tôi muốn nói cơ sở

sửa Xem:

http://www.c-sharpcorner.com/UploadFile/rajeshvs/ConsNDestructorsInCS11122005010300AM/ConsNDestructorsInCS.aspx

có nó nói:

using System; 
class Base 
{ 

public Base() 
{ 
    Console.WriteLine("BASE 1"); 
} 
public Base(int x) 
{ 
    Console.WriteLine("BASE 2"); 
} 
} 

class Derived : Base 
{ 
public Derived():base(10) 
{ 
    Console.WriteLine("DERIVED CLASS"); 
} 
} 

class MyClient 
{ 
public static void Main() 
{ 
    Derived d1 = new Derived(); 
} 
} 

đầu ra Chương trình này

BASE2

có nguồn gốc CLASS

17

Trên thực tế, các nhà xây dựng lớp được thừa kế được thực hiện đầu tiên, nhưng các biên dịch C# chèn một cuộc gọi đến constructor lớp cơ sở như tuyên bố đầu tiên của các nhà xây dựng có nguồn gốc .

Vì vậy: dẫn xuất được thực hiện trước tiên, nhưng "trông giống như" cơ sở được thực hiện trước tiên.

+2

Đây là một trong những trường hợp ngữ cảnh quan trọng - trong thuật ngữ CLR, hàm tạo có nguồn gốc được thực hiện trước tiên. Trong thuật ngữ C#, hàm tạo cơ sở được thực hiện trước tiên. Có một vài điều kỳ quặc như thế này mà các thông số kỹ thuật không đồng ý; ví dụ, về việc cấu trúc có một hàm tạo parameterless hay không. –

+6

Thực ra, có vẻ như tôi đã nói quá nhanh.Bây giờ tôi đã tham khảo ý kiến ​​spec, và trong khi nó nói rằng constructor-initializer được thực hiện trước khi constructor-body, được tính như được bao gồm trong constructor tổng thể. Vì vậy, bạn hoàn toàn phù hợp với cả hai quan điểm :) –

127

Các trình tạo lớp cơ sở được gọi trước các hàm tạo lớp dẫn xuất, nhưng các trình khởi tạo lớp dẫn xuất được gọi trước các trình khởi tạo lớp cơ sở. Ví dụ. trong đoạn mã sau:

public class BaseClass { 

    private string sentenceOne = null; // A 

    public BaseClass() { 
     sentenceOne = "The quick brown fox"; // B 
    } 
} 

public class SubClass : BaseClass { 

    private string sentenceTwo = null; // C 

    public SubClass() { 
     sentenceTwo = "jumps over the lazy dog"; // D 
    } 
} 

Trình tự thực hiện là: C, A, B, D.

Kiểm tra những bài viết này 2 MSDN:

0

Hàm tạo cơ sở sẽ được gọi là đầu tiên, nếu không, trong trường hợp e "các công cụ khác" của bạn phải sử dụng các biến thành viên được khởi tạo bởi hàm tạo cơ sở của bạn, bạn sẽ nhận được các lỗi thời gian biên dịch vì các thành viên lớp của bạn sẽ chưa được khởi tạo.

+0

Biến thành viên không có cùng khái niệm phân công xác định dưới dạng biến cục bộ. Chúng có giá trị mặc định. Điều thú vị trong C# là khởi tạo biến được chạy * trước * hàm tạo cơ sở thay vì sau. (Java có hành vi thứ hai.) –

0

base (?) Được gọi trước khi thực hiện bất kỳ công việc nào trong hàm tạo con.

Điều này đúng, ngay cả khi bạn rời khỏi: cơ sở() (. Trong trường hợp này, các nhà xây dựng cơ sở 0-tham số được gọi là)

Nó hoạt động tương tự như java,

public Child() 
{ 
    super(); // this line is always the first line in a child constructor even if you don't put it there! *** 
} 

*** Ngoại lệ: Thay vào đó tôi có thể đưa vào siêu (1,2,3). Nhưng nếu tôi không gọi một cách rõ ràng, siêu() được gọi.

+0

Nó hơi khác với Java, vì thứ tự của các biến khởi tạo biến. Xem http://pobox.com/~skeet/csharp/constructors.html để biết chi tiết. –

+0

Đó là lý do tại sao tôi sử dụng từ "tương tự" –

4

Như những người khác đã nói, hàm tạo cơ sở được gọi là đầu tiên. Tuy nhiên, các nhà xây dựng không thực sự là điều đầu tiên xảy ra.

Hãy nói rằng bạn có các lớp học như thế này:

class A {} 

class B : A {} 

class C : B {} 

Thứ nhất, initializers lĩnh vực sẽ được gọi theo thứ tự nhất có nguồn gốc từ các lớp học ít nhất có nguồn gốc từ. Vì vậy, các trình khởi tạo trường đầu tiên của C, sau đó B, sau đó A.

Các nhà xây dựng sau đó sẽ được gọi theo thứ tự ngược lại: Nhà xây dựng đầu tiên của A, sau đó B, sau đó C.

0

Cuộc gọi xây dựng được gọi là (được kích hoạt) từ dưới lên và được thực thi từ trên xuống dưới. Do đó, nếu bạn có Class C kế thừa từ lớp B kế thừa từ lớp A, khi bạn tạo một thể hiện của lớp C, hàm tạo cho C được gọi, mà lần lượt gọi hướng dẫn cho B, một lần nữa gọi hàm khởi tạo cho A. Bây giờ constructor cho A được thực hiện, sau đó hàm tạo cho B được thi hành, thì hàm tạo cho C được thi hành.

30

Đừng cố nhớ điều đó, hãy cố gắng giải thích cho chính mình những gì đã xảy ra. Hãy tưởng tượng rằng bạn có lớp cơ sở có tên là Animal và một lớp dẫn xuất có tên là Dog. Lớp dẫn xuất bổ sung một số chức năng cho lớp cơ sở. Do đó khi hàm tạo của lớp dẫn xuất được thực thi, cá thể lớp cơ sở phải có sẵn (để bạn có thể thêm chức năng mới vào nó). Đó là lý do tại sao các hàm tạo được thực hiện từ cơ sở đến các phần tử dẫn xuất nhưng các hàm hủy được thực thi theo cách ngược lại - đầu tiên là các hàm hủy có nguồn gốc và sau đó là các trình phá hủy cơ sở.

(Đây là đơn giản nhưng nó sẽ giúp bạn trả lời câu hỏi này trong tương lai mà không cần phải thực sự ghi nhớ này.)

+4

Đừng nhớ điều đó, hãy hiểu nó. Công việc tốt đẹp. –

1

cơ sở Constructor được gọi đầu tiên. Nhưng initializer của các trường trong lớp dẫn xuất được gọi là đầu tiên.

Trình tự gọi là

  1. có nguồn gốc trường lớp initializer
  2. cơ sở trường lớp initializer
  3. lớp cơ sở constructor
  4. lớp có nguồn gốc constructor

(Bạn có thể đối xử với 2 và 3 để xây dựng lớp cơ sở.)

Taken từ CSharp Language Speification 5.0:

10.11.3 Constructor thực hiện

initializers biến được chuyển thành câu lệnh gán, và các báo cáo phân được thực hiện trước khi gọi các constructor dụ lớp cơ sở . Thứ tự này đảm bảo rằng tất cả các trường cá thể được khởi tạo bởi các trình khởi tạo biến của chúng trước khi bất kỳ câu lệnh nào có quyền truy cập vào cá thể đó được thực hiện. Với ví dụ

using System; 
class A 
{ 
    public A() { 
     PrintFields(); 
    } 
    public virtual void PrintFields() {} 
} 
class B: A 
{ 
    int x = 1; 
    int y; 
    public B() { 
     y = -1; 
    } 
    public override void PrintFields() { 
     Console.WriteLine("x = {0}, y = {1}", x, y); 
    } 
} 

khi new B() được sử dụng để tạo ra một thể hiện của B, các đầu ra sau đây được tạo ra:

x = 1, y = 0 

Giá trị của x là 1 vì initializer biến được thực hiện trước constructor instance của lớp cơ sở được gọi. Tuy nhiên, giá trị của y là 0 (giá trị mặc định là int) do việc gán đến y không được thực hiện cho đến sau khi hàm tạo của lớp cơ sở trả về. Sẽ rất hữu ích khi nghĩ về các biến khởi tạo biến thể và các khởi tạo hàm khởi tạo như các câu lệnh được tự động chèn trước phần thân của hàm tạo. Ví dụ

using System; 
using System.Collections; 
class A 
{ 
    int x = 1, y = -1, count; 
    public A() { 
     count = 0; 
    } 
    public A(int n) { 
     count = n; 
    } 
} 
class B: A 
{ 
    double sqrt2 = Math.Sqrt(2.0); 
    ArrayList items = new ArrayList(100); 
    int max; 
    public B(): this(100) { 
     items.Add("default"); 
    } 
    public B(int n): base(n – 1) { 
     max = n; 
    } 
} 

chứa nhiều trình khởi tạo biến; nó cũng chứa constructor initializers của cả hai form (base và this). Ví dụ tương ứng với mã được hiển thị bên dưới, trong đó mỗi nhận xét cho biết câu lệnh được chèn tự động (cú pháp được sử dụng cho lời gọi hàm xây dựng được chèn tự động không hợp lệ, nhưng chỉ phục vụ cho minh họa cơ chế).

using System.Collections; 
class A 
{ 
    int x, y, count; 
    public A() { 
     x = 1;        // Variable initializer 
     y = -1;        // Variable initializer 
     object();       // Invoke object() constructor 
     count = 0; 
    } 
    public A(int n) { 
     x = 1;        // Variable initializer 
     y = -1;        // Variable initializer 
     object();       // Invoke object() constructor 
     count = n; 
    } 
} 
class B: A 
{ 
    double sqrt2; 
    ArrayList items; 
    int max; 
    public B(): this(100) { 
     B(100);        // Invoke B(int) constructor 
     items.Add("default"); 
    } 
    public B(int n): base(n – 1) { 
     sqrt2 = Math.Sqrt(2.0);   // Variable initializer 
     items = new ArrayList(100); // Variable initializer 
     A(n – 1);       // Invoke A(int) constructor 
     max = n; 
    } 
} 
Các vấn đề liên quan