Trước hết, chúng ta hãy điều khoản chính xác. Đó không phải là bộ sưu tập . Đó là bộ khởi tạo mảng . Bộ khởi tạo bộ sưu tập luôn theo sau một hàm tạo cho một loại bộ sưu tập. Trình khởi tạo mảng chỉ hợp pháp trong bộ khởi tạo khai báo cục bộ hoặc trường hoặc trong biểu thức tạo mảng.
Bạn hoàn toàn chính xác cần lưu ý rằng đây là quy tắc lẻ. Hãy để tôi mô tả tính kỳ lạ của nó chính xác:
Giả sử bạn có phương thức M lấy một mảng int. Tất cả đây là những quy phạm pháp luật:
int[] x = new[] { 10, 20, 30 };
int[] y = new int[] { 10, 20, 30 };
int[] z = new int[3] { 10, 20, 30 };
M(new[] { 10, 20, 30 });
M(new int[] { 10, 20, 30 });
M(new int[3] { 10, 20, 30 });
Nhưng
int[] q = {10, 20, 30}; // legal!
M({ 10, 20, 30 }); // illegal!
Nó có vẻ như một trong hai "đơn độc" mảng initializer nên được quy phạm pháp luật ở khắp mọi nơi rằng "trang trí" một là, hoặc hư không. Thật kỳ lạ khi có biểu thức giả này chỉ hợp lệ trong trình khởi tạo, không phải ở bất kỳ nơi nào khác mà biểu thức là hợp pháp.
Trước khi cả hai chỉ trích và bảo vệ lựa chọn này, tôi muốn nói điều đó trước hết, sự khác biệt này là một tai nạn lịch sử. Không có lý do thuyết phục nào cho nó. Nếu chúng ta có thể loại bỏ nó mà không phá vỡ mã, chúng tôi sẽ làm như vậy. Nhưng chúng ta không thể. Chúng tôi đã thiết kế C# từ đầu một lần nữa hôm nay tôi nghĩ rằng tỷ lệ cược là tốt mà các "đơn độc" khởi tạo mảng mà không "mới" sẽ không phải là một cú pháp hợp lệ. Vì vậy, trước tiên, hãy để tôi đưa ra một số lý do tại sao các bộ khởi tạo mảng KHÔNG được phép như là các biểu thức và nên được cho phép trong các bộ khởi tạo biến cục bộ. Sau đó, tôi sẽ đưa ra một số lý do cho điều ngược lại.
Lý do tại sao initializers mảng không được phép như biểu thức:
Mảng initializers vi phạm sở hữu tốt đẹp mà {
luôn có nghĩa là giới thiệu của một khối mới của mã. Trình phân tích cú pháp phục hồi lỗi trong IDE phân tích cú pháp khi bạn đang gõ thích sử dụng dấu ngoặc nhọn như một cách thuận tiện để báo khi nào câu lệnh chưa hoàn thành; nếu bạn thấy:
if (x == M(
{
Q(
Sau đó, nó là khá dễ dàng cho các biên tập mã để đoán rằng bạn đang thiếu ))
trước {
. biên tập viên sẽ giả định rằng Q(
là sự khởi đầu của một tuyên bố và nó bị thiếu kết thúc.
Nhưng nếu trình khởi tạo mảng là biểu thức pháp lý thì có thể là số bị thiếu là )})){}
sau số Q
.
Thứ hai, bộ khởi tạo mảng làm biểu thức vi phạm nguyên tắc tốt đẹp là tất cả phân bổ đống có "mới" trong chúng ở đâu đó.
Lý do tại sao initializers mảng nên được cho phép trong lĩnh vực và địa phương initializers:
Hãy nhớ rằng initializers mảng đã được thêm vào ngôn ngữ trong v1.0, người dân địa phương trước khi ngầm đánh máy, các loại vô danh, hoặc suy luận kiểu trên mảng. Quay trở lại những ngày chúng tôi không có thú vị "mới [] {10, 20, 30}" cú pháp, như vậy mà không initializers mảng bạn phải nói:
int[] x = new int[] { 10, 20, 30 };
mà dường như rất dư thừa! Tôi có thể thấy lý do tại sao họ muốn có được "int mới []" ra khỏi đó.
Khi bạn nói
int[] x = { 10, 20, 30 };
nó không phải là cú pháp mơ hồ; trình phân tích cú pháp biết rằng đây là một bộ khởi tạo mảng và không phải là sự khởi đầu của một khối mã (không giống như trường hợp tôi đã đề cập ở trên.) Cũng không phải là loại không rõ ràng; rõ ràng rằng initializer là một mảng ints từ ngữ cảnh.
Vì vậy, đối số đó biện minh cho lý do tại sao bộ khởi tạo mảng C# 1.0 được phép trong trình khởi tạo cục bộ và trường nhưng không được phép trong ngữ cảnh biểu thức.
Nhưng đó không phải là thế giới chúng ta đang có trong ngày hôm nay. Chúng ta đã thiết kế điều này từ đầu ngày hôm nay có lẽ chúng ta sẽ không có các bộ khởi tạo mảng không có "mới". Ngày nay, tất nhiên chúng tôi nhận ra rằng giải pháp tốt hơn là:
var x = new[] { 10, 20, 30 };
và biểu thức đó hợp lệ trong mọi ngữ cảnh. Bạn có thể rõ ràng gõ nó vào bên "tuyên bố" hoặc bên "khởi tạo" của =
nếu bạn thấy phù hợp, hoặc bạn có thể để trình biên dịch suy ra các loại của một trong hai bên hoặc cả hai.
Vì vậy, tổng hợp, có, bạn đúng là không nhất quán rằng các trình khởi tạo mảng chỉ có thể trong khai báo cục bộ và trường chứ không phải trong ngữ cảnh biểu thức. Có một lý do tốt cho điều đó mười năm trước, nhưng trong thế giới hiện đại với suy luận kiểu, không còn lý do chính đáng nào cho nó nữa. Nó chỉ là một tai nạn lịch sử vào thời điểm này.
Bạn có thể thấy điều này hữu ích: http://stackoverflow.com/questions/7351453/why-cant-i-use-the-array-initializer-with-an-implicitly-typed-variable (không hoàn toàn trùng lặp) –