Tại sao có một ràng buộc () mới trong C # nhưng không có ràng buộc tương tự nào khác?


19

Trong thế hệ C #, chúng ta có thể khai báo một ràng buộc cho một tham số loại Tđể có một hàm tạo mặc định, bằng cách nói where T : new(). Tuy nhiên, không có loại ràng buộc nào khác như thế này là hợp lệ - new(string)ví dụ, v.v.

Từ một thiết kế ngôn ngữ và / hoặc quan điểm thực hiện, lý do cho điều này là gì?

Có một cái gì đó trong cách các nhà xây dựng làm việc hoặc theo cách hệ thống loại được triển khai mà cấm điều này (hoặc ít nhất là làm cho nó khó hơn)? Nếu vậy, nó là cái gì? Tôi nhớ lại việc đọc ở đâu đó mà default(T)thực sự biên dịch new T()cho T : struct. Có liên quan đến điều này, có thể?

Hay nó chỉ đơn giản là một quyết định thiết kế được đưa ra để tránh làm cho ngôn ngữ quá phức tạp?


new(string)không phải là một ràng buộc xây dựng mặc định. Câu hỏi của bạn tương đương với câu nói "Tại sao không có các ràng buộc yêu cầu chữ ký của nhà xây dựng cụ thể?" Rất có thể bởi vì một ràng buộc như vậy sẽ không đặc biệt hữu ích.
Robert Harvey

3
@RobertHarvey Vâng, đó chính xác là những gì tôi đang nói. Về cơ bản, tôi đang hỏi liệu có thứ gì đó làm cho các nhà xây dựng mặc định đặc biệt khôn ngoan thực hiện hay không nếu đó chỉ là một lựa chọn tùy ý để bao gồm cái này chứ không phải cái kia.
Theodoros Chatzigiannakis

Các constructor mặc định rất hữu ích theo những cách cụ thể và quan trọng nhất định. Ví dụ, họ tạo ra một loại dễ dàng tuần tự hóa.
Robert Harvey

6
Chữ ký ctor cụ thể có thể hữu ích. Ví dụ: nếu biến loại của bạn bị hạn chế là Bộ sưu tập <T> với một ctor của T (Bộ sưu tập <T>), bạn biết rằng bạn có thể xây dựng các bộ sưu tập mới được cung cấp khác. Cho dù sự hữu ích đó có xứng đáng với sự phức tạp thêm hay không, là một câu hỏi.
Phoshi

Câu trả lời:


5

Đối với câu trả lời có thẩm quyền, tôi sẽ giới thiệu cho bạn câu trả lời của Eric Lippert cho câu hỏi đó trên StackOverflow vài năm trước, một đoạn trích được trích dẫn ngắn gọn dưới đây.

Tuy nhiên, trong trường hợp cụ thể này, tôi chắc chắn có thể cung cấp cho bạn một số lý do tại sao tôi sẽ đẩy lùi tính năng này nếu nó xuất hiện trong một cuộc họp thiết kế như một tính năng có thể có cho phiên bản ngôn ngữ trong tương lai.

...

Tôi nói rằng chúng ta nên làm toàn bộ tính năng hoặc không làm gì cả. Nếu điều quan trọng là có thể hạn chế các loại để có các hàm tạo cụ thể, thì hãy thực hiện toàn bộ tính năng và hạn chế các loại trên cơ sở các thành viên nói chung chứ không chỉ các hàm tạo.


2
Câu nói đó, được đưa ra khỏi bối cảnh, là rất sai lệch. Điều đó cho thấy Eric nghĩ rằng Microsoft nên "đi hết con đường", đó hoàn toàn không phải là vị trí của anh ấy. Trên thực tế, anh ta chống lại tính năng được đề xuất.
Robert Harvey

1
Cảm ơn, đây không phải là câu trả lời cho câu hỏi của tôi một phần: Gần cuối câu trả lời của anh ấy, Eric Lippert đề cập rằng đó là một hạn chế của IL và bao gồm cả tính năng này sẽ yêu cầu bổ sung IL. Sẽ thật hoàn hảo nếu bạn có thể cung cấp một nguồn về những gì IL được tạo cho phần được triển khai - nghĩa là, gọi chung là một hàm tạo mặc định.
Theodoros Chatzigiannakis

@TheodorosChatzigiannakis: Tại sao bạn không kích hoạt Trình dịch ngược của Telerik và tự mình tìm hiểu?
Robert Harvey

2
@RobertHarvey Tôi không nghĩ rằng nó gợi ý một vị trí cho anh ta, nhưng tôi đã bao gồm một trích dẫn bổ sung để nhấn mạnh vị trí của anh ta.
Chris Hannon

1
Hmm, F # có nhiều cách nâng cao hơn để hạn chế một loại , như kiểm tra thời gian biên dịch nếu một lớp có toán tử. Có lẽ, F # cần một hệ thống ràng buộc mạnh hơn C # do kiểm tra loại rất nghiêm ngặt. Tuy nhiên, ngôn ngữ này có thể triển khai các cách nâng cao để tạo thành lớp trên .Net Framework.
OnesimusUnbound

16

Dịch ngược (theo gợi ý của Robert Harvey) mang lại những điều sau đây, cho bất kỳ ai quan tâm. Phương pháp này:

static T GenericMake<T>()
    where T : new()
{
    return new T();
}

Rõ ràng, khi được biên dịch, trở thành thế này:

private static T GenericMake<T>()
    where T : new()
{
    T t;
    T t1 = default(T);
    if (t1 == null)
    {
        t = Activator.CreateInstance<T>();
    }
    else
    {
        t1 = default(T);
        t = t1;
    }
    return t;
}
  • Nếu Tlà một loại giá trị, new()trở thành default(T).
  • Nếu Tlà một loại tham chiếu, new()hoạt động bằng cách sử dụng sự phản chiếu. Activator.CreateInstance()cuộc gọi nội bộ RuntimeType.CreateInstanceDefaultCtor().

Vì vậy, đó là - bên trong, các hàm tạo mặc định thực sự đặc biệt đối với C # liên quan đến CLR. Cung cấp cho các nhà xây dựng khác việc điều trị tương tự sẽ rất tốn kém, ngay cả khi có một số trường hợp sử dụng hợp lệ cho các ràng buộc phức tạp hơn trong thuốc generic.


4
Hấp dẫn. Tại sao cuộc gọi trùng lặp default(T) cho các loại giá trị?
Avner Shahar-Kashtan

2
@ AvnerShahar-Kashtan Tôi không biết. Nó có thể là một tạo tác của quá trình biên dịch / dịch ngược, giống như tbiến (có thể được thay thế bằng các returncâu lệnh lồng nhau ).
Theodoros Chatzigiannakis
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.