Tại sao tôi không thể gọi SomeGenericMethod<SomeGenericType<>>
Câu trả lời đơn giản nhất là: vì language specification nói như vậy:
4,4 loại Xây dựng
Một tuyên bố kiểu generic, bởi chính nó, biểu thị một loại chung chung không bị ràng buộc được sử dụng như một "kế hoạch chi tiết" để tạo thành nhiều loại khác nhau, bằng cách này của việc áp dụng các đối số kiểu. Các đối số kiểu được viết trong dấu ngoặc nhọn (< và>) ngay sau tên của loại chung. Một loại bao gồm ít nhất một đối số kiểu được gọi là kiểu được xây dựng. Kiểu được xây dựng có thể được sử dụng ở hầu hết các địa điểm bằng ngôn ngữ mà tên loại có thể xuất hiện. Loại chung chung không liên kết chỉ có thể được sử dụng trong một biểu thức typeof (§7.6.11).
4.4.3 ràng buộc và không ràng buộc kiểu
Các loại ràng buộc hạn đề cập đến một loại không chung hoặc một loại generic không ràng buộc. Loại giới hạn thuật ngữ đề cập đến một loại không chung chung hoặc một loại được xây dựng. Loại không liên kết đề cập đến đối tượng được khai báo theo tuyên bố loại. Một kiểu generic không liên kết không phải là một kiểu, và không thể được sử dụng như kiểu của một biến, đối số hoặc giá trị trả về, hoặc là một kiểu cơ sở. Cấu trúc duy nhất trong đó một kiểu chung không liên kết có thể được tham chiếu là biểu thức typeof (§7.6.11).
Tại sao thông số C# nói như vậy? Bởi vì CLI spec mệnh lệnh đó là tốt:
II.9.4 Instantiating kiểu generic
...
CLI không hỗ trợ instantiation một phần của các kiểu generic. Và các loại chung sẽ không xuất hiện ở bất kỳ đâu trong các đốm chữ ký siêu dữ liệu.
Ok, giờ hãy dừng với pháp lý.Câu trả lời thực tế cho câu hỏi của bạn là:
Khi bạn gọi SomeMethod<SomeType>()
cho lần đầu tiên, CLR sẽ gọi trình biên dịch JIT, mà sẽ đọc SomeMethod<T>
, thay T
, và tạo mã thực thi mới đại diện cho SomeMethod<SomeType>
.
Khi bạn gọi SomeMethod<SomeOtherType>()
, quá trình cần được lặp lại, mã mới sẽ được tạo cho SomeMethod<SomeOtherType>
.
Bạn không thể chỉ tạo mã hợp lệ cho loại chung chung không bị ràng buộc như Generic<>
. Trong trường hợp chung, JIT không thể biết được mã đại diện nào để tạo ra mà không biết T
.
- Nếu
T
là một string
và phương pháp của bạn khai báo một biến cục bộ kiểu T
, JIT sẽ phân bổ không gian ngăn xếp hoặc sử dụng một thanh ghi với kích thước của một con trỏ bản địa.
- Nếu
T
là Guid
, JIT sẽ phải phân bổ không gian ngăn xếp cho giá trị 128 bit cố định. Nó không thể tạo mã nếu nó không biết T
là gì.
Do đó, nói chung, bạn không thể tạo mã thực thi cho loại không liên kết. Lý do bạn cho là có thể chỉ làm điều đó cho đoạn mã bạn đã cung cấp, điều này sẽ yêu cầu vỏ đặc biệt và mã gọi điện của bạn sẽ ngừng hoạt động nếu bạn thêm một số T
địa phương theo phương thức PrintType
. Như generics phải được tái sử dụng trên các hội đồng, mã gọi không thể giả định bất cứ điều gì về phương pháp được gọi là.
Về cơ bản 'typeof' có thể lấy một tên lớp chung mà không có kiểu generic được xác định, nhưng nếu bạn chuyển kiểu như kiểu chung thì nó phải là kiểu được xác định hoàn toàn mà' Generic <> 'không phải. – juharr
@juharr Như thường lệ ở đây trong SO, câu trả lời tốt nhất cho đến nay là trong các ý kiến. Vì vậy, nó là an toàn để nói rằng là ** không thể ** để làm như vậy? – talles
Tôi nghĩ rbaghbanli đang nói cùng một điều. Nhưng không có bạn không thể vượt qua 'Generic <>' như một loại chung chung. Lưu ý nếu bạn làm 'typeof (Generic