2010-04-30 25 views
5

Mã sau đây không biên dịch được, tạo ra một "Widget phải là một kiểu không trừu tượng với một hàm tạo". Tôi nghĩ rằng trình biên dịch có tất cả thông tin cần thiết. Đây có phải là một lỗi? Một giám sát? Hoặc là có một số kịch bản mà điều này sẽ không hợp lệ?Tại sao không phải ràng buộc chung() chung mới của một lớp với các tham số tùy chọn trong hàm tạo?

public class Factory<T> where T : new() 
{ 
    public T Build() 
    { 
     return new T(); 
    } 
} 

public class Widget 
{ 
    public Widget(string name = "foo") 
    { 
     Name = name; 
    } 

    public string Name { get; set; } 
} 

public class Program 
{ 
    public static void Main() 
    { 
     var widget = new Widget(); // this is valid 
     var factory = new Factory<Widget>(); // compiler error 
    } 
} 
+0

Phân trang Eric Lippert .... Tôi nghĩ điều này sẽ giảm xuống các tham số tùy chọn là tính năng trình biên dịch, nhưng các ràng buộc chung là CLR. Vì vậy các tham số tùy chọn được thay thế bởi trình biên dịch và JIT chỉ nhìn thấy các tham số (requied). – Richard

+0

@Richard: Đó là vấn đề cơ bản ở đây. Các tham số tùy chọn cũng có một số hiệu ứng phụ lạ đối với phiên bản, vì lý do chính xác này ... –

Trả lời

7

Trong khi điều này hợp lý nên hoạt động, thật không may là không. CLR vẫn thấy hàm tạo của bạn như là một hàm tạo dựa trên tham số.

Hãy nhớ rằng, trong khi C# hỗ trợ các tham số tùy chọn, điều này được thực hiện ở cấp trình biên dịch, tại thời gian biên dịch. Kiểu cơ bản vẫn chỉ chứa một hàm khởi tạo lấy một tham số duy nhất. Đối với CLR, "thông số mặc định" được chuyển đổi thành thuộc tính, như vậy:

public Widget(([Optional, DefaultParameterValue("foo")] string name) { // ... 

CLR là thời gian chạy đa ngôn ngữ. Generics được tạo ra để làm việc ở mức CLR, cho tất cả các ngôn ngữ, vì vậy các ràng buộc phải đúng trong các ngôn ngữ không có các tham số mặc định. Ngôn ngữ không bắt buộc phải hiểu thuộc tính OptionalAttribute, cũng như DefaultParameterValueAttribute, do đó, điều này không thể làm việc thống nhất cho tất cả các ngôn ngữ, do đó nó không được phép.


Edit:

Đáp lại bình luận của bạn:

Những gì tôi không hiểu là tại sao các biên dịch C# không thể tạo mã cần thiết để đáp CLR

Về mặt lý thuyết, nhóm trình biên dịch C# có thể có ngôn ngữ tạo ra hai hàm tạo riêng biệt, thay vì một hàm tạo được đánh dấu bằng các thuộc tính. Điều này, có khả năng, phát nổ thành nhiều constructor, như các tham số được đặt tên tạo ra các khả năng cho nhiều, nhiều kết hợp có thể có của "constructors" (hoặc phương thức gọi cho phương thức), đặc biệt khi có nhiều đối số. Cá nhân tôi vui mừng vì họ không, vì nó sẽ gây nhầm lẫn do sự dư thừa của các phương thức và các nhà xây dựng trong các kiểu được tạo ra, điều này sẽ khiến API công cộng trông rất khác với mã đã tạo ra nó. Hãy constructor sau đây:

public Widget(
      int id = 0, 
      string name = "foo", 
      float width=1.0f, 
      float height=1.0f, 
      float depth=1.0f 
     ) { // ... 

Were bạn tự động tạo ra tất cả các kết hợp có thể ở đây, trình biên dịch sẽ cần phải tạo ra thầu cho các nhà xây dựng đơn này, kể từ khi có N! những cách có thể để gọi cho điều này ...

+0

@Joshua: Trình biên dịch C# tạo mã tôi dán ở trên. Đây là cách nó hoạt động - nó không tạo ra một hàm tạo parameterless, mà là một hàm tạo không bắt buộc. Tôi sẽ chỉnh sửa để thêm chi tiết ... –

+0

Ok, cảm ơn, điều đó giải thích tại sao nó không hoạt động. Tôi vẫn tự hỏi ý nghĩa của việc tạo ra hàm tạo parameterless sẽ là gì. –

+0

@Joshua: Tôi đã chỉnh sửa câu trả lời của mình để giải thích lý do tại sao đây có thể là ý tưởng tồi ... Làm cho ý nghĩa hơn bây giờ? Hãy nhớ rằng, nó không chỉ là tùy chọn, bạn cũng có thể sử dụng các tham số có tên, vì vậy các tham số N có nghĩa là N! các kết hợp có thể cần phải được tạo ... –

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