TLDR: Đây là một lỗi đã biết từ lâu. Lần đầu tiên tôi viết về nó vào năm 2010:
https://bloss.msdn.microsoft.com/ericlippert/2010/01/18/a-definite-assocate-anomaly/
Nó vô hại và bạn có thể bỏ qua nó một cách an toàn, và tự chúc mừng mình vì đã tìm thấy một lỗi khó hiểu.
Tại sao trình biên dịch không thực thi mà Emailphải được gán chắc chắn?
Ồ, nó làm, trong một thời trang. Nó chỉ có một ý tưởng sai về điều kiện ngụ ý rằng biến đó chắc chắn được gán, như chúng ta sẽ thấy.
Tại sao mã này biên dịch nếu cấu trúc được tạo trong một cụm riêng biệt, nhưng nó không biên dịch nếu cấu trúc được xác định trong lắp ráp hiện có?
Đó là mấu chốt của lỗi. Lỗi này là hậu quả của giao điểm của cách trình biên dịch C # thực hiện kiểm tra gán xác định trên các cấu trúc và cách trình biên dịch tải siêu dữ liệu từ các thư viện.
Xem xét điều này:
struct Foo
{
public int x;
public int y;
}
// Yes, public fields are bad, but this is just
// to illustrate the situation.
void M(out Foo f)
{
OK, tại thời điểm này chúng ta biết gì? flà một bí danh cho một biến loại Foo, do đó, bộ lưu trữ đã được phân bổ và chắc chắn ít nhất là ở trạng thái nó ra khỏi bộ cấp phát lưu trữ. Nếu có một giá trị được đặt trong biến bởi người gọi, giá trị đó là ở đó.
Chúng ta yêu cầu gì? Chúng tôi yêu cầu phải fđược chỉ định chắc chắn tại bất kỳ điểm nào mà kiểm soát rời khỏi Mbình thường. Vì vậy, bạn sẽ mong đợi một cái gì đó như:
void M(out Foo f)
{
f = new Foo();
}
mà thiết lập f.xvà f.ycác giá trị mặc định của họ. Nhưng những gì về điều này?
void M(out Foo f)
{
f = new Foo();
f.x = 123;
f.y = 456;
}
Điều đó cũng sẽ ổn thôi. Nhưng, và đây là kicker, tại sao chúng ta chỉ cần gán các giá trị mặc định để thổi bay chúng sau đó? Trình kiểm tra phân công xác định của C # sẽ kiểm tra xem mọi trường có được gán không! Đây là hợp pháp:
void M(out Foo f)
{
f.x = 123;
f.y = 456;
}
Và tại sao điều đó không hợp pháp? Đó là một loại giá trị. flà một biến và nó đã chứa một giá trị hợp lệ của loại Foo, vì vậy hãy đặt các trường và chúng ta đã hoàn thành, phải không?
Đúng. Vậy lỗi là gì?
Lỗi mà bạn đã phát hiện ra là: vì tiết kiệm chi phí, trình biên dịch C # không tải siêu dữ liệu cho các trường riêng của các cấu trúc trong các thư viện được tham chiếu . Siêu dữ liệu đó có thể rất lớn và nó sẽ làm chậm trình biên dịch để giành được rất ít chiến thắng để tải tất cả vào bộ nhớ mỗi lần.
Và bây giờ bạn sẽ có thể suy ra nguyên nhân của lỗi bạn đã tìm thấy. Khi trình biên dịch kiểm tra xem tham số out có được gán chắc chắn hay không, nó sẽ so sánh số lượng các trường đã biết với số trường được khởi tạo xác định và trong trường hợp của bạn, nó chỉ biết về các trường công khai bằng 0 vì siêu dữ liệu của trường riêng không được tải . Trình biên dịch kết luận "không có trường nào được yêu cầu, không có trường nào được khởi tạo, chúng tôi tốt."
Giống như tôi đã nói, lỗi này đã tồn tại hơn một thập kỷ và những người như bạn thỉnh thoảng khám phá lại và báo cáo nó. Nó vô hại, và nó khó có thể được sửa chữa bởi vì sửa nó là lợi ích gần như bằng không nhưng chi phí hiệu năng lớn.
Và tất nhiên, lỗi này không repro cho các trường cấu trúc riêng trong mã nguồn trong dự án của bạn, vì rõ ràng trình biên dịch đã có thông tin về các trường riêng trong tay.