2012-05-11 18 views
5

Tôi đã tạo một lớp chung chung cần khởi tạo loại triển khai của nó, vì vậy kiểu triển khai phải có một hàm tạo ít tham số có thể truy cập. Có vẻ như hạn chế mới() có thể thực hiện công việc nhưng nó thực thi kiểu triển khai để có một hàm tạo công khai khi tôi có nó bên trong (nhưng có thể truy cập được vì cả hai đều nằm trong cùng một assembly).Có cách nào để xác định nơi T: new() hạn chế nhưng với constructor nội bộ?

  1. Có lý do nào để ép buộc công khai thay vì "có thể truy cập" không?
  2. Có cách nào để làm những gì tôi cần không?

Xin cảm ơn trước.

EDIT: Lý do để làm điều này là tôi có một lớp X phải được sử dụng thông qua Singleton. Lớp Singleton là một lớp chung và tôi muốn làm cho constructor lớp X nội bộ để tránh người dùng bên ngoài truy cập vào đối tượng một cách sai (gọi hàm tạo).

+2

Làm cho lớp nội bộ và công thức xây dựng được công khai. Nếu lớp học phải được công khai, thì không bạn không thể. –

Trả lời

5

Điều này không được ngôn ngữ C# cho phép như được nêu trong phần 4.4.3 của đặc điểm kỹ thuật Loại liên kết và không được phân cách.

Nếu ràng buộc là các nhà xây dựng chế new(), loại A phải không abstract và phải có một constructor parameterless công cộng. Điều này là hài lòng nếu một trong những điều sau là đúng.

  • A là một loại giá trị, vì tất cả các loại giá trị có một constructor mặc định nào
  • A là một tham số kiểu có chế cosntructor
  • A là một tham số kiểu có kiểu giá trị hạn chế
  • A là một lớp không phải là abstract và chứa một tuyên bố rõ ràng public constuctor không có tham số
  • A không phải là abstract và có một hàm tạo mặc định.

Lỗi trình biên dịch nếu bất kỳ điều kiện nào trong số này không được đáp ứng. Nếu bạn thấy mình có các loại công khai nhưng chỉ với các nhà xây dựng nội bộ, thì rất có thể chúng thực sự là các kiểu nội bộ với các nhà xây dựng công cộng.

Tôi khuyên bạn nên thay đổi loại trình truy cập của mình thành internal và hàm tạo của nó là public và làm cho nó không có tham số. Sau đó, hàm tạo public không có tham số của bạn có thể gọi đến một hàm tạo không tham số private hoặc internal để thực hiện bất kỳ công việc khởi tạo bổ sung nào.

internal class C<T> where : T new() 
{ 
    public C() : this(new T()) { 
    } 

    private C(T t) { 
     // Do additional initialization 
    } 
} 

Nhớ rằng mẫu đó bị giới hạn, nhưng không có gì ngăn bạn sử dụng phương pháp private thay thế.

internal class C<T> where T : new() { 
    public C() { 
     T t = new T(); 
     InitializeClass(t); 
    } 

    private void InitializeClass(T t) { 
     throw new NotImplementedException(); 
    } 
} 

Theo bản cập nhật của bạn, đây là ví dụ nhỏ về một đĩa đơn công khai.

public class Singleton<T> where T : new() 
{ 
    public static Singleton<T> Current { 
     get; 
     private set; 
    } 

    internal Singleton() : this(new T()) { 
    } 

    private Singleton(T t) { 
     Current = this; 
     // Do whatever you need to with T 
    }   

    public String Name { 
     get; 
     set; 
    } 
} 

Cách sử dụng

// Somewhere in your internal assembly 
Singleton<String> singleton = new Singleton<String>(); 

// In an external assembly 
Singleton.Current.Name = "SoMoS"; 

Bạn thậm chí không cần phải sử dụng nhà thầu trong thời trang mà một trong hai, bạn có thể cũng giống như dễ dàng làm điều gì đó đơn giản.

public class Singleton<T> where T : new() 
{ 
    public static Singleton<T> Current { 
     get; 
     private set; 
    } 

    internal Singleton() { 
     T t = new T(); 
     // Do stuff with T 
    } 

    public String Name { 
     get; 
     set; 
    } 
} 

Generics thể không phải là con đường để đi nếu bạn không thể thiết kế nó để phù hợp với yêu cầu của bạn. Generics chỉ có thể làm được rất nhiều và không giải quyết mọi vấn đề. Có những thứ như Mẫu Nhà máy, Tiêm, v.v.

+0

Cảm ơn, hãy xem bản chỉnh sửa của tôi để hiểu lý do cho người xây dựng nội bộ –

+0

Đã cập nhật câu trả lời của tôi. Bạn có thể nghĩ gì về thiết kế của bạn nhiều hơn một chút, bởi vì generics có thể không phù hợp nhất. –

2

Có lý do nào để ép buộc công khai thay vì "có thể truy cập" không?

hạn truy cập là rất bối cảnh nhạy cảm, Generics là không, bởi kiến ​​trúc. Trong trường hợp cụ thể của bạn internal có thể truy cập được, nhưng generics được tạo cho các giải pháp chung.

Có cách nào để làm những gì tôi cần không?

Dựa trên điểm đầu tiên, không, điều đó là không thể, cũng như tôi không biết.

+0

Vâng, theo quan điểm của tôi, trình biên dịch có thể kiểm tra tại thời gian biên dịch nếu hàm khởi tạo có thể truy cập được hoặc không chỉ gây ra lỗi nếu không thể gọi hàm mới từ lớp chung. Dù sao, cảm ơn cho lời giải thích. –

+0

@SoMoS: Vấn đề là một loại 'T' có một ràng buộc' mới() 'có thể được truyền cho các thường trình trong các assembly khác nhau. Mặc dù có thể có một trình biên dịch trong một số trường hợp để xác định rằng một tham số kiểu cụ thể 'T' không bao giờ có thể được truyền bên ngoài một assembly cụ thể, trong nhiều trường hợp suy luận như vậy là không thể. Cho phép các kiểu với các hàm tạo tham số 'nội bộ' chỉ thỏa mãn các ràng buộc' mới() 'khi trình biên dịch có thể suy ra rằng nó sẽ an toàn sẽ ngụ ý có các quy tắc khá kỳ lạ khi sử dụng như vậy được cho phép. – supercat

+0

@SoMos: những gì bạn đang yêu cầu, là một số đặc biệt 'nội bộ mới()' định nghĩa, nơi bạn có thể xác định Nó hoàn toàn. Tại sao không phỏng đoán nó ngay bây giờ? Tôi nghĩ rằng đó là về các loại chia sẻ giữa các hội đồng khác nhau.Điều gì sẽ xảy ra nếu tôi muốn sử dụng chung một kiểu thời gian chạy nào đó mà ctor không thể truy cập từ "bên ngoài" .... – Tigran

1

Generics là giải pháp chung, do đó nếu bạn sử dụng ràng buộc "mới", giải pháp của bạn phải làm việc với mọi lớp thực hiện một ctor công khai.

Nếu bạn muốn triển khai giải pháp chung cho một loại lớp cụ thể, bạn có thể xác định lớp cơ sở trừu tượng triển khai thực hiện một hàm tạo nội bộ như vậy. Thực hiện một giải pháp chung cho lớp cơ sở trừu tượng này và sử dụng

* nơi T: MyBaseClassWithInternalCtor *

như hạn chế.

+0

Âm thanh như một giải pháp tốt đẹp. Cảm ơn! –

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