2010-10-06 61 views
18

Tôi biết không thể kế thừa các hàm tạo trong C#, nhưng có lẽ có một cách để làm những gì tôi muốn làm.C#: kế thừa các hàm tạo

Tôi có một lớp cơ sở được thừa kế bởi nhiều lớp khác và có phương thức Init thực hiện một số tham số khởi tạo tham số 1. Tất cả các lớp kế thừa khác cũng cần khởi tạo này, nhưng tôi cần phải tạo các hàm tạo riêng cho tất cả chúng như sau:

public Constructor(Parameter p) { 
    base.Init(p); 
} 

Điều đó hoàn toàn vi phạm nguyên tắc DRY! Làm thế nào tôi có thể có tất cả các công cụ cần thiết khởi tạo mà không tạo ra hàng chục nhà xây dựng?

+2

Tệ hơn vi phạm nguyên tắc DRY đang vi phạm nguyên tắc bất biến. 'Init' như tên của một phương thức thường là một dấu hiệu mạnh mẽ rằng các đối tượng không cần thiết tồn tại trong các trạng thái không hợp lệ, nơi điều duy nhất chúng tốt cho là gây ra lỗi. –

+1

C# không thực sự tuân theo DRY. Điều này có thể khó chịu nhưng ... thành thật mà nói, bạn không thể nói với tôi rằng bạn không mệt mỏi khi gõ 'public',' protected', và 'private' hơn và hơn và hơn? –

+1

@ SlippD.Thompson: Đó là một lĩnh vực khác mà C++ thực sự là * ít hơn * wordy hơn các ngôn ngữ dễ dàng hơn ... Cái trước tôi vừa thấy là liên quan đến việc trưng ra các hàm tạo cơ sở trong một lớp dẫn xuất. –

Trả lời

47

Bạn không cần phải tạo tải trọng của các nhà xây dựng, tất cả đều có cùng mã; bạn chỉ tạo một, nhưng có các lớp dẫn xuất gọi hàm tạo cơ sở:

public class Base 
{ 
    public Base(Parameter p) 
    { 
     Init(p) 
    } 

    Init(Parameter p) 
    { 
     // common initialisation code 
    } 
} 

public class Derived : Base 
{ 
    public Derived(Parameter p) : base(p) 
    { 

    } 
} 
+1

Đó là những gì tôi cần. Mặc dù tôi sẽ phải tạo các hàm tạo cho các lớp không có chúng, tôi sẽ không phải lặp lại mã. – Alex

+1

lý do bỏ phiếu xuống? –

+1

Tôi muốn C# có thứ gì đó giống như các hàm tạo kế thừa của C++, nó vẫn gây phiền nhiễu khi gọi tất cả các hàm tạo cơ sở –

7

Thay đổi hàm init với nó là các nhà xây dựng cho lớp cơ sở, và sau đó gọi nó từ các đối tượng di truyền như thế này:

public InheritedObject(Parameter p) : base(p) 
{ 
} 

Các nhà xây dựng cơ sở sẽ được gọi trước khi bất kỳ mã trong các nhà xây dựng chính nó chạy .

2

Cái gì đó như thế này?

public Constructor(Parameter p) : base(p) { 

} 

Và lớp cơ sở:

public Base(Parameter p) 
{ 
    Init(p); 
} 

Bạn thậm chí có thể đánh dấu phương pháp Init của bạn như là ảo, vì vậy bạn có thể làm một số override ngọt ngào trong các lớp học khác của bạn, nếu cần thiết! ;)

public virtual void Init() { } 

và trong các lớp học khác của bạn:

public override void Init() { base.Init(); //Do other stuff } 
+2

Mặc dù bạn phải rất cẩn thận khi gọi một phương thức ảo từ một hàm khởi tạo - hàm tạo của lớp con sẽ không chạy khi phương thức ghi đè được gọi bởi các siêu lớp, do đó, các biến thành viên vv sẽ không được khởi tạo. – thecoop

+0

true :) nhưng bạn sẽ thấy rằng vấn đề thực sự nhanh chóng .. – Arcturus

+1

Phương pháp init ảo dường như vô nghĩa, mặc dù. Normaly bạn nên tránh làm công việc trong các nhà xây dựng, và chỉ sử dụng chúng để khởi tạo, và nếu nó chỉ là khởi tạo, thì tại sao không chỉ sử dụng constructor? – AHM

5

Cách duy nhất để không lặp lại base.Init gọi là thay vì gọi các nhà xây dựng cơ sở

class Base 
{ 
    public Base(Parameter p) 
    { 
    this.Init(p) 
    } 

    private void Init(Parameter p) 
    { 
     ... 
    } 
} 

class Inherited : Base 
{ 
    public Inherited(Parameter p) 
    : base(p) 
    { 
     // other constructor logic, but Init is already called. 
    } 
} 
3

Bạn có thể không kế thừa các nhà xây dựng nhưng bạn có thể gọi chúng từ các nhà thầu có nguồn gốc của trẻ. Nếu bạn tạo các lớp cơ sở mặc định là constructor riêng, nó sẽ buộc bạn phải chọn một hàm tạo cơ sở mỗi khi bạn tạo một lớp dẫn xuất.

class A 
{ 
    protected A(int x) 
    { 

    } 
} 
class B : A 
{ 
    B(int x) 
     : base(x) 
    { 

    } 
}