xem xét sau hai kiểu dữ liệu:gì là sự khác biệt giữa indexer mảng và bất kỳ indexer đối tượng khác
class C
{
public int I { get; set; }
}
struct S
{
public int I { get; set; }
}
Hãy cố gắng sử dụng chúng trong danh sách, ví dụ:
var c_list = new List<C> { new C { I = 1 } };
c_list[0].I++;
var s_list = new List<S> { new S { I = 1 } };
s_list[0].I++; // (a) CS1612 compilation error
Đúng như dự đoán, có là lỗi biên dịch trên dòng (a)
: CS1612 Cannot modify the return value of 'List<UserQuery.S>.this[int]' because it is not a variable
. Điều này là tốt, bởi vì thực sự chúng tôi đang cố gắng sửa đổi bản sao tạm thời của S
, đó là giá trị r trong việc đưa ra ngữ cảnh.
Nhưng chúng ta hãy cố gắng làm điều tương tự cho một mảng:
var c_arr = new[] { new C { I = 1 } };
c_arr[0].I++;
var s_arr = new[] { new S { I = 1 } };
s_arr[0].I++; // (b)
Và .. làm việc này.
Nhưng
var s_arr_list = (IList<S>) s_arr;
s_arr_list[0].I++;
sẽ không biên dịch, như mong đợi.
Nếu chúng ta nhìn vào IL sản xuất, chúng ta sẽ thấy sau đây:
IL_0057: ldloc.1 // s_arr
IL_0058: ldc.i4.0 // index
IL_0059: ldelema UserQuery.S // manager pointer of element
ldelema
tải địa chỉ của phần tử mảng để phía trên cùng của ngăn xếp đánh giá. Hành vi như vậy được mong đợi với các mảng fixed
và các con trỏ không an toàn. Nhưng đối với bối cảnh an toàn thì đây là một chút bất ngờ. Tại sao có một trường hợp không rõ ràng đặc biệt cho mảng? Bất kỳ lý do tại sao không có tùy chọn để đạt được hành vi tương tự cho các thành viên của các loại khác?
Tại sao bạn thấy 'ldelema' bất ngờ cho ngữ cảnh an toàn? Nó tải một tham chiếu được quản lý (do đó được kiểm soát bởi GC), như 'ldloca' hoặc' ldflda'. Khi bạn sử dụng 'ref' trong C#, đây chính xác là nó. – IllidanS4