Tôi thấy sự khác biệt này trong hành vi và đặc biệt là hành vi trong trường hợp cấu trúc đáng ngạc nhiên và không trực quan - điều gì đang xảy ra? Điều gì hiện mặc định arg trên cấu trúc stuct phục vụ? Nếu nó vô dụng tại sao cho phép biên dịch này?
Nó không phục vụ gì cả. Mã IL được phát ra sẽ không tạo ra một lời gọi tới hàm tạo với tham số mặc định, nhưng sẽ gọi default(Test)
. Dường như hoàn toàn hợp lý rằng trình biên dịch sẽ phát ra một cảnh báo nói rằng hàm tạo sẽ không được gọi ra (mặc dù đó là một chi tiết thực hiện). Tôi nộp một vấn đề trên http://connect.microsoft.com
Nếu chúng ta nhìn vào mã IL được tạo ra cho:
Test myTest = new Test();
bool valid = myTest.IsValid;
Chúng tôi sẽ thấy:
IL_0000: ldloca.s 00 // myTest
IL_0002: initobj UserQuery.Test // default(Test);
IL_0008: ldloca.s 00 // myTest
IL_000A: call UserQuery+Test.get_IsValid
Lưu ý các cuộc gọi được thực hiện tại IL không phải là một phương pháp gọi hàm khởi tạo (trông giống như sau: call Test..ctor
) , nó đã tạo một cuộc gọi tới initobj
:
Khởi tạo từng trường của loại giá trị tại địa chỉ được chỉ định thành tham chiếu rỗng hoặc 0 của loại nguyên thủy phù hợp. Không giống như Newobj, initobj không gọi phương thức hàm tạo. Initobj được thiết kế để khởi tạo các loại giá trị, trong khi newobj được sử dụng để cấp phát và khởi tạo các đối tượng.
Điều đó có nghĩa trình biên dịch chỉ đơn thuần là bỏ qua hàm tạo với các tham số mặc định, cho đến khi C# -6.0 bị cấm khai báo một hàm tạo như vậy.
@JonSkeet mất này để độ sâu lớn trong câu trả lời của mình để Does using "new" on a struct allocate it on the heap or stack?
Sửa:
Tôi thực sự hỏi Mads Torgerson một câu hỏi liên quan đến việc sử dụng mới của các nhà xây dựng parameterless trong C# -6.0 mà tôi nghĩ có liên quan, và ông nói:
@Yuval và những người khác, liên quan đến nhà xây dựng parameterless trên cấu trúc: những điều cần nhận thức được rằng, trước và bây giờ, nhà xây dựng không nhất thiết chạy trên cấu trúc . Tất cả những gì chúng tôi đã làm là thêm khả năng có một hàm tạo tham số không được đảm bảo để chạy. Có là không có cách hợp lý để có các cấu trúc được đảm bảo là đã được khởi tạo và không có tham số không hỗ trợ điều đó.
Những điều mà các nhà xây dựng không có tham số giúp đỡ là cho phép bạn có một hàm tạo không tham số.
Tôi nghĩ rằng một nguồn chính gây nhầm lẫn là 'S mới()' được phép có nghĩa là 'mặc định (S)'. Đó là một sai lầm lịch sử trong ngôn ngữ và tôi mong muốn tôi có thể mang nó đi. Tôi sẽ không khuyến khích bất kỳ ai sử dụng 'mới S()' trên cấu trúc không có tham số hàm tạo. Theo như tôi có thể nói, điều này là bởi vì cú pháp mặc định (S) không tồn tại trong C# 1.0, vì vậy đây chỉ là cú pháp được sử dụng cho nhận giá trị mặc định của một cấu trúc.
Đúng là việc triển khai trình biên dịch cho đến nay "tối ưu" 'T mới()' có nghĩa cơ bản là mặc định (T) khi T là cấu trúc. Đó là thực sự là một lỗi - nó luôn luôn được gọi là một thực tế constructor parameterless nếu có một - mà có thể có được tất cả cùng, vì nó được cho phép trong IL. Chúng tôi đang sửa lỗi này, để chúng tôi sẽ gọi hàm tạo ngay cả trong trường hợp chung.
Ngữ nghĩa do đó là sạch: S mới() là cách duy nhất để chạy một constructor parameterless trên một cấu trúc, và nó luôn chạy mà constructor - thậm chí thông qua Generics.
Tôi sẽ nói rằng bằng cách không chuyển một đối số thì bạn đang gọi hàm _implicit_ [default constructor] (http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx) trên các cấu trúc đặt tất cả thành viên với giá trị mặc định của họ, thay vì gọi hàm tạo của bạn –
@ DanielJ.G. Vâng, đó là trường hợp - nhưng quan điểm của tôi là không trực quan. Nó không phải về những gì đang xảy ra nhưng về lý do tại sao điều này biên dịch mà không cần cảnh báo. – Ricibob
Có thể viết các phương thức/hàm tạo mà không có cách hợp lý để bạn gọi trực tiếp chúng (không giống như ở đây bạn có thể cung cấp tham số, và mặc định là "vô nghĩa") ngoại trừ phản xạ. Trình biên dịch C# sẽ phải cực kỳ phức tạp hơn (và có lẽ phải giải quyết vấn đề dừng) để * ngăn chặn * bạn biên dịch mã như vậy. Và bạn có thể * có ý định * rằng nó chỉ có thể sử dụng được thông qua sự phản chiếu, cho tất cả các trình biên dịch biết. –