2013-05-19 38 views
26

Có sự khác biệt nào giữa A và B không?Sự khác nhau giữa một lớp có hàm tạo riêng và lớp niêm phong có hàm tạo riêng là gì?

Class A có xây dựng tư nhân:

class A 
{ 
    private A() 
    { } 
} 

Class B được niêm phong và có một constructor tin:

sealed class B 
{ 
    private B() 
    { } 
} 
+0

Tại sao bạn muốn một lớp có hàm tạo riêng tư ở vị trí đầu tiên? –

+5

@MarkusMeskanen Lớp có thể có phương thức nhà máy tĩnh công cộng cần phải là cách duy nhất để khách hàng có thể tạo một thể hiện của lớp. –

+3

@MarkusMeskanen [Singletons] (http://msdn.microsoft.com/en-us/library/ff650316.aspx) –

Trả lời

39

A có thể được kế thừa bởi một lớp lồng nhau, trong khi B không thể được kế thừa. Đây là hoàn toàn hợp pháp:

public class A { 
    private A() { } 

    public class Derived : A { } 
} 

Lưu ý rằng bất kỳ mã có thể tạo ra một new A.Derived() hoặc kế thừa từ A.Derived (constructor của nó là công khai), nhưng không có lớp khác ngoài văn bản nguồn A có thể kế thừa trực tiếp từ A.

Một sử dụng điển hình cho một cái gì đó như thế này là một lớp học với giá trị enum giống như nhưng có thể có hành vi tùy chỉnh:

public abstract class A { 
    private A() { } 

    public abstract void DoSomething(); 

    private class OneImpl : A { 
    public override void DoSomething() { Console.WriteLine("One"); } 
    } 

    private class TwoImpl : A { 
    public override void DoSomething() { Console.WriteLine("Two"); } 
    } 

    public static readonly A One = new OneImpl(); 
    public static readonly A Two = new TwoImpl(); 
} 
+0

Vui vẻ cung cấp +1 của tôi ở đây :-) – Jon

+0

Haha! Bây giờ đó là * không * contrived trong đó bạn thực sự có thể muốn làm điều đó (mặc dù không phổ biến).+1 :) –

+2

Về cơ bản, điều này cũng giống như việc cung cấp các nhà xây dựng khác trên A, ngoại trừ đây là các kiến ​​trúc siêu đẳng cấp lồng nhau "ưa thích" –

5

Dựa trên bài viết thứ hai nếu điều này là các nhà xây dựng duy nhất bạn sẽ không thể để tạo một thể hiện của Class A hoặc Class B. Vì Class A có một hàm tạo riêng, bạn không thể lấy được nó từ mức bảo vệ của nó, cũng như bạn không thể lấy được từ B với dấu kín.

Inheritance (C# Programming Guide)

nguồn gốc lớp Tiếp cận Base Class Members Một lớp học có nguồn gốc có quyền truy cập cho công chúng, bảo vệ, nội bộ, và bảo vệ các thành viên nội bộ của một lớp cơ sở. Mặc dù một lớp dẫn xuất thừa hưởng các thành viên private của một lớp cơ sở, nó không thể truy cập các thành viên đó. Tuy nhiên, tất cả những thành viên cá nhân vẫn còn hiện diện trong lớp dẫn xuất và có thể thực hiện công việc tương tự mà họ sẽ làm trong lớp cơ sở. Ví dụ: giả sử rằng phương thức lớp cơ sở được bảo vệ truy cập trường riêng tư. Trường phải có mặt trong lớp dẫn xuất cho phương thức lớp cơ sở thừa kế để hoạt động chính xác.

Private Constructors (C# Programming Guide)

Một xây dựng tư nhân là một constructor dụ đặc biệt. Nó là thường được sử dụng trong các lớp chỉ chứa các thành viên tĩnh. Nếu một lớp học có một hoặc nhiều nhà xây dựng riêng và không có nhà thầu công khai, thì các lớp khác (ngoại trừ các lớp lồng nhau) không được phép tạo trường hợp của lớp này.

+0

Hơi đạo đức, tôi có thể tạo bất kỳ số lượng phiên bản nào của A hoặc B nếu họ có phương pháp nhà máy ngay cả khi họ không có bất kỳ nhà thầu nào ngoài những người được chỉ định. –

+0

Bạn không thể nhận được A hoặc B. Bạn không thể dervie A vì các nhà xây dựng tư nhân. Câu hỏi có thể là: Nếu có một lớp học với một nhà xây dựng tư nhân là có bất kỳ sự khác biệt nếu bạn đánh dấu nó niêm phong. – jannagy02

+0

@ jannagy02: Tôi đã cập nhật điều đó khi bạn đang nhập nhận xét của mình :-) – Harrison

1

Lớp sealed có thể được khởi tạo nhưng lớp có trình tạo riêng tư thì không thể. Cả hai đều không cho phép thừa kế, nhưng đó không phải là mục tiêu của một nhà xây dựng riêng.

Lý do bạn sử dụng hàm tạo riêng tư là dừng việc khởi tạo. Điều này thường được sử dụng trong các phương thức nhà máy tĩnh, nơi bạn phải gọi MyClass::Create(...) để tạo một cá thể.

Điều này không liên quan gì đến việc niêm phong, điều này sẽ dừng kế thừa. Nếu bạn sử dụng một hàm tạo riêng để dừng kế thừa, thì bạn đang sử dụng cách tiếp cận sai. Có nhiều cách để có được xung quanh một hàm tạo riêng cho kế thừa.

4

Có một sự khác biệt nhỏ mà bạn có thể nhận được, để thực hiện với Phân tích mã.

xem xét mã này:

public class Base 
{ 
    public virtual void Function() 
    { 
    } 
} 

public class Derived: Base 
{ 
    public static Derived Create() 
    { 
     return new Derived(); 
    } 

    private Derived() 
    { 
     // Code analysis warning: CS2214 "Do not call overridable methods in constructors". 
     Function(); 
    } 
} 

Có một Mã Phân tích cảnh báo cho các nhà xây dựng có nguồn gốc, bởi vì chúng ta đang truy cập vào một phương pháp ảo từ nó, đó là một điều xấu.

Tuy nhiên, nếu bạn thực hiện Derived bị đóng kín, cảnh báo Phân tích mã sẽ biến mất.

Vì vậy, có một số lượng nhỏ và giả mạo sự khác biệt cho bạn. ;)

0

Nếu một lớp được bịt kín, nó sẽ không thể định nghĩa một lớp mà có nguồn gốc từ nó. Một lớp với một hàm tạo riêng có thể được khởi tạo bằng các phương thức nhà máy trong lớp, cũng không được kế thừa bởi các lớp lồng nhau (tùy thuộc vào mức truy cập và các hàm tạo của chúng, có thể được thừa kế bởi mã bên ngoài). Ngoài ra, mã ngoài tùy ý có thể khai báo các lớp xuất phát từ mã đó và đáp ứng ràng buộc new(). Nếu lớp dẫn xuất không thể gọi hàm tạo cơ sở, thì các hàm tạo riêng của nó sẽ không có cách nào khác ngoài việc ném một ngoại lệ, sự cố hoặc treo, nhưng hành vi như vậy sẽ không thể phát hiện được cho đến khi thực hiện xây dựng một cá thể; mã sẽ biên dịch tốt.

0
public class Test 
{ 


    private Test() 
    { 
     Debug.WriteLine("private constructor has been called in class Test"); 
    } 

    public virtual string Run() 
    { 
     return "Test.Run"; 
    } 

    public static Test GetTestRequest() 
    { 
     return new Test(); 
    } 

    public static DerivedTest GetDerivedTestRequest() 
    { 
     return new DerivedTest(); 
    } 

    public class DerivedTest:Test 
    { 
     public DerivedTest() 
     { 
      Debug.WriteLine("public constructor has been called in derived class DerivedTest."); 
     } 

     public override string Run() 
     { 
      return "DerivedTest.Run"; 
     } 
    } 
} 

Debug.WriteLine (Test.GetTestRequest(). Chạy()); Debug.WriteLine (Test.GetDerivedTestRequest(). Chạy());

============================================== ============== Output:

xây dựng tư nhân đã được gọi là trong class Test Test.Run

xây dựng tư nhân đã được gọi là trong class Test constructor nào đã được được gọi trong lớp dẫn xuất DerivedTest. DerivedTest.Run

Vì vậy, một lớp lồng nhau có thể được bắt nguồn từ lớp cơ sở bên ngoài có hàm tạo riêng duy nhất.

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