2009-02-18 21 views
29

Giả Tôi tuyên bố một danh sách chung chứa các giá trị của một cấu trúc kiểu:Trong C#, các giá trị trong danh sách có được liệt kê là <struct> không?

struct MyStruct { 
    public MyStruct(int val1, decimal val2) : this() { 
     Val1 = val1; 
     Val2 = val2; 
    } 
    public int Val1 {get; private set;} 
    public decimal Val2 {get; private set;} 
} 

List<MyStruct> list; 

Liệu Danh mục <> cửa hàng mỗi giá trị cá nhân như một cấu trúc đóng hộp, phân bổ riêng trên heap? Hay thông minh hơn thế?

Trả lời

33

Không có quyền anh.

"Không, sẽ không có quyền anh. Đó là một trong những mục tiêu thiết kế chính của Generics".

http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/359cf58a-f53d-478e-bc31-1507e77c9454/

"Nếu một loại giá trị được sử dụng cho loại T, trình biên dịch tạo ra một thực hiện các lớp List<T> đặc biệt cho loại giá trị. Điều đó có nghĩa là một yếu tố danh sách của một đối tượng List<T> không phải được đóng hộp trước khi phần tử có thể được sử dụng, và sau khoảng 500 phần tử danh sách được tạo, bộ nhớ được lưu không phải là phần tử danh sách quyền anh lớn hơn bộ nhớ được sử dụng để tạo ra lớp thực hiện. "

http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx

+0

Có gì "và sau khoảng 500 phần tử danh sách được tạo, bộ nhớ được lưu không phải là phần tử danh sách quyền anh hùng lớn hơn bộ nhớ được sử dụng để tạo lớp triển khai" nghĩa là gì? Có một số loại bất lợi? –

+0

@MarsonMao Không có bất lợi. Nói cách khác, nó có nghĩa là nếu một danh sách là ngu ngốc và nó đã làm cấu trúc hộp, sau đó bộ nhớ được sử dụng bởi danh sách sẽ tăng gấp đôi ở khoảng 500 yếu tố. Vì nó không có cấu trúc hộp, thì bộ nhớ được sử dụng bởi 500 phần tử sẽ nhỏ hơn đáng kể so với nếu nó có. –

+0

@Marson Mao Generics trong C# không giống như C++, chúng không phải lúc nào cũng tạo mã cho từng loại duy nhất. Đối với các loại tham chiếu, chúng sẽ sử dụng cùng một mã cơ bản vì kích thước của con trỏ không thay đổi với kiểu tham chiếu. Nhưng đối với các loại giá trị, kích thước khác nhau nên phiên bản Danh sách phải được tạo duy nhất, điều này có chi phí bộ nhớ vì có nghĩa là bây giờ có một bản sao khác của mã danh sách . Xin lỗi nếu tôi không rõ ràng. Xem https://msdn.microsoft.com/en-us/library/f4a6ta2h.aspx –

1

Không có quyền anh, đó là lý do tại sao nó nhanh hơn một chút so với cách không chung chung.

8

Không, List<T> không đóng bất kỳ thứ gì. Nội bộ nó lưu trữ các giá trị của nó trong một mảng đơn giản:

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable 
{ 
    // Fields 
    private const int _defaultCapacity = 4; 
    private static T[] _emptyArray; 
    private T[] _items; 
    private int _size; 
0

Không đấm bốc, đó là một trong những Benefits of Generics:

List<int> list1 = new List<int>();  
// No boxing, no casting: 
list1.Add(3); 

// Compile-time error: 
// list1.Add("It is raining in Redmond."); 
2

Danh sách lưu trữ tất cả mọi thứ trong mảng kiểu T. Không có đấm bốc, nhưng mảng được cấp phát trên heap.

19

Nó không được đóng hộp, nhưng dữ liệu sẽ trở thành một bản sao của bản gốc, và mỗi khi bạn lấy dữ liệu ra, nó sẽ sao chép lại. Điều này có xu hướng làm cho nó dễ dàng để mất những thay đổi. Như vậy, bạn nên cố gắng không viết các cấu trúc có thể thay đổi được. Trừ khi MyStruct thực sự đại diện cho một đơn vị đo lường (hoặc tương tự), biến nó thành một lớp. Và nếu nó một thước đo, làm cho nó không thay đổi (không có thành viên có thể đặt trước công khai).

Và một trong hai cách, không hiển thị trường! Sử dụng thuộc tính ;-p

Ví dụ:

struct MyStruct { 
    public MyStruct(int val1, decimal val2) { 
     this.val1 = val1; 
     this.val2 = val2; 
    } 
    private readonly int val1; 
    private readonly decimal val2; 
    public int Val1 {get {return val1;}} 
    public decimal Val2 {get {return val2;}} 
} 

Hoặc cách khác (C# 3.0):

struct MyStruct { 
    public MyStruct(int val1, decimal val2) : this() { 
     Val1 = val1; 
     Val2 = val2; 
    } 
    public int Val1 {get; private set;} 
    public decimal Val2 {get; private set;} 
} 
+0

Vâng, tôi đánh giá cao điều đó. Thấy một số người chỉ ra điều này, tôi sẽ sử dụng cấu trúc của bạn trong câu hỏi ban đầu, để nhấn mạnh trở lại vào quyền anh và giảm giá trị ngữ nghĩa của cấu trúc. –

3
typeof(List<>) // or informally List`1 

... là một kiểu generic. Các kiểu chung hoặc các kiểu tham số hóa đặc biệt ở chỗ chúng được biên dịch theo cách thông thường nhưng vào thời gian chạy chúng được biên dịch lại một lần nữa tùy thuộc vào việc sử dụng chúng.

Nếu bạn đặt một ValueType trong danh sách chung chung, ví dụ:Danh sách < int> hành vi thời gian chạy là để đe dọa rằng nếu nó được lưu trữ kiểu int (đó là bản sao theo giá trị). Boxing không cần phải diễn ra bởi vì bạn không cần phải đối xử như thể loại List này là 1 cái gì đó khác với int.

Trước .NET 2.0, điều này không thể thực hiện được vì vậy lớp ArrayList khét tiếng duy trì một mảng các đối tượng có nghĩa ValueType (ints hoặc structs) phải được đóng hộp để được đặt trong vùng chứa đó.

Điều này không nên nhầm lẫn với các Generics Java, cái gì đó hoàn toàn khác. Java Generics đã được thực hiện với loại tẩy xoá mà không cung cấp cho bạn tăng hiệu suất tương tự. Những gì Java làm là một khi trình biên dịch đã hoàn thành kiểm tra loại, nó sẽ đúc tất cả mọi thứ để đối tượng. Đây là lý do tại sao bạn không thể làm phản chiếu với các Generics Java trong khi bạn có thể với hệ thống kiểu .NET chung.

+0

Tôi không biết về trình biên dịch thời gian chạy ... Thật thú vị. 1 cũng cho thông tin Java. –

Các vấn đề liên quan