2010-10-08 25 views
29

Cách tiêu chuẩn để có danh sách trống, được đọc chỉ trong C# là gì?C#/.NET tương đương với Bộ sưu tập Java. <T> emptyList()?

ETA: Đối với những người hỏi "tại sao?": Tôi có một phương pháp ảo mà trả về một IList (hay đúng hơn, sau câu trả lời, một IEnumerable), và việc thực hiện mặc định là rỗng. Bất kể việc trả về danh sách nào cũng nên được đọc bởi vì viết cho nó sẽ là một lỗi, và nếu ai đó cố gắng, tôi muốn dừng lại và bắt lửa ngay lập tức, thay vì đợi lỗi xuất hiện một cách tinh tế sau này.

+4

Bạn sẽ làm gì với một danh sách chỉ đọc có sản phẩm nào dù sao? Chỉ tò mò thôi. – goenning

+0

Tôi đoán có một số «IEnumerable » có lẽ là câu trả lời đúng ở đây - là một số thực sự cần thiết? hoặc chỉ là một bộ sưu tập chỉ đọc rỗng? –

+1

chỉ tò mò, tại sao bạn cần một danh sách chỉ đọc rỗng? –

Trả lời

18

Cá nhân, tôi nghĩ rằng đây là tốt hơn so với bất kỳ câu trả lời khác:

static readonly IList<T> EmptyList = new T[0]; 
  • Mảng thực hiện IList<T>.
  • Bạn không thể thêm vào mảng.
  • Bạn không thể gán cho một phần tử trong một mảng trống (vì có không có gì).
  • Điều này theo ý kiến ​​của tôi, đơn giản hơn rất nhiều so với new List<T>().AsReadOnly().
  • Bạn vẫn nhận được trả lại IList<T> (nếu bạn muốn).

Ngẫu nhiên, đây là những gì Enumerable.Empty<T>() thực sự sử dụng dưới mui xe, nếu tôi nhớ chính xác. Vì vậy, về mặt lý thuyết bạn thậm chí có thể làm (IList<T>)Enumerable.Empty<T>() (mặc dù tôi thấy không có lý do chính đáng để làm điều đó).

+0

Câu trả lời của bạn thực sự chỉ có ý nghĩa với tôi về các ý kiến ​​gắn liền với [câu trả lời của Virtlink] (https://stackoverflow.com/a/10659068/712526). – jpaugh

+1

Kể từ 4.6 bạn thậm chí không cần phải cung cấp đối tượng của riêng bạn nữa, chỉ cần trả về Array.Empty (). – ZunTzu

21

Bạn chỉ có thể tạo ra một danh sách:

List<MyType> list = new List<MyType>(); 

Nếu bạn muốn một sản phẩm nào IEnumerable<T>, sử dụng Enumerable.Empty<T>():

IEnumerable<MyType> collection = Enumerable.Empty<MyType>(); 

Nếu bạn thực sự muốn có một danh sách readonly, bạn có thể làm:

IList<MyType> readonlyList = (new List<MyType>()).AsReadOnly(); 

Điều này trả về ReadOnlyCollection<T>, triển khai IList<T>.

+2

Tôi cũng nghĩ điều này nhưng sau đó đã thấy yêu cầu chỉ đọc. Sau đó, tôi nghĩ rằng những gì sẽ là điểm của một danh sách chỉ đọc rỗng . Tôi đang thiếu gì? –

+0

Không thực sự là một chỉ đọc 'Danh sách ' ... –

+0

@Jay: Tôi cũng đã thêm tùy chọn đó ... –

7
IList<T> list = new List<T>().AsReadOnly(); 

Hoặc, nếu bạn muốn một IEnumerable<>:

IEnumerable<T> sequence = Enumerable.Empty<T>(); 
+1

Kể từ 4.6, có một giải pháp tốt hơn: IList list = Array.Empty (); – ZunTzu

-1

gì về:

readonly List<T> mylist = new List<T>(); 

Không chắc lý do tại sao bạn muốn nó chỉ đọc; điều đó không có ý nghĩa gì trong hầu hết các kịch bản mà tôi có thể nghĩ đến.

+2

Ngoài ra, điều này không làm cho danh sách chỉ đọc. – Timwi

+0

Re: tại sao, xem câu hỏi đã chỉnh sửa ở trên. –

4

Nếu bạn muốn có một danh sách có nội dung không thể được sửa đổi, bạn có thể làm:

ReadOnlyCollection<Foo> foos = new List<Foo>().AsReadOnly(); 
2

Để mở rộng trên Dan Tao's answer, việc triển khai sau có thể được sử dụng theo cách tương tự như Enumerable.Empty<T>(), bằng cách chỉ định List.Empty<T>() thay thế.

public static class List 
{ 
    public static IList<T> Empty<T>() 
    { 
     // Note that the static type is only instantiated when 
     // it is needed, and only then is the T[0] object created, once. 
     return EmptyArray<T>.Instance; 
    } 

    private sealed class EmptyArray<T> 
    { 
     public static readonly T[] Instance = new T[0]; 
    } 
} 

Edit: Tôi thay đổi mã ở trên để phản ánh kết quả của một cuộc thảo luận với Dan Tao về lười biếng so với khởi háo hức của trường Instance.

+0

Khởi tạo lười biếng của một mảng có độ dài bằng không? Cá nhân tôi nghĩ rằng đó là một sai lầm, vì nó làm tăng tính phức tạp, sẽ làm cho hiệu suất hơi tồi tệ hơn (gọi phương thức bổ sung trên mọi truy cập), có điều kiện đua (hai chủ đề gọi là 'List.Empty ()' cùng một lúc) và mua bạn hầu như không có gì (làm thế nào để bạn nghĩ rằng chi phí khởi tạo của một mảng không có độ dài không so sánh với mảng của JIT biên dịch một lớp mới?). Đi với trường công khai 'tĩnh readonly' được khởi tạo háo hức, hoặc - nếu lương tâm của bạn không cho phép nó - một trường riêng cộng với phương thức' Empty'. Chỉ cần hai xu của tôi! –

+1

Hai chủ đề nhận các đối tượng khác nhau không phải là vấn đề. Hiệu suất không bị ảnh hưởng khi cuộc gọi là [rất có khả năng được nêu trong] (https://blogs.msdn.com/b/ericgu/archive/2004/01/29/64717.aspx). Tôi không thấy làm thế nào một dòng logic thực sự có thể làm tăng thêm độ phức tạp. Và cuối cùng nhưng không kém phần quan trọng: Tôi vừa kiểm tra việc thực hiện 'Enumerable.Empty ()' và nó rất giống với những gì tôi đã viết.Nếu cần danh sách trống của tất cả các loại trên khắp nơi, hãy sử dụng phương pháp này vì nó tiết kiệm phân bổ và rác. Nếu chỉ hiếm khi cần một danh sách trống, hãy sử dụng 'readonly' tĩnh của bạn. – Virtlink

+0

Bạn có lẽ là đúng để được phòng thủ, như bình luận của tôi đã chắc chắn tách tóc. Tuy nhiên, các đối tượng khác nhau có thể là một vấn đề nếu, ví dụ, bạn có một số mã quan trọng phụ thuộc vào kiểm tra 'if (list == List.Empty ())'. Ngoài ra, cách tiếp cận này tiết kiệm phân bổ và rác thải như thế nào? –

6

Bắt đầu với .net 4.6 bạn cũng có thể sử dụng:

IList<T> emptyList = Array.Empty<T>(); 

này chỉ tạo ra một trường hợp mới một lần cho tất cả các loại khác nhau mà bạn chỉ định như T.

+0

Giống như String.Empty, cũng luôn tham chiếu cùng một cá thể thay vì tạo một chuỗi rỗng mới. –

+0

@David De Sloovere chuỗi trống có chữ "" cũng tham chiếu đến cùng một cá thể nhờ vào chuỗi ký tự (chỉ cần nói cho những người đọc cảm thấy có nghĩa vụ phải thay thế "" bởi String.Empty). – ZunTzu

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