cách thêm một loạt các mục vào biến IList


81

không có AddRange()phương pháp cho IList<T>.

Làm cách nào để thêm danh sách các mục vào a IList<T>mà không cần lặp lại các mục và sử dụng Add()phương thức?

Câu trả lời:


65

AddRangeđược xác định trên List<T>, không phải giao diện.

Bạn có thể khai báo biến List<T>thay vì IList<T>hoặc ép kiểu nó để có List<T>quyền truy cập AddRange.

((List<myType>)myIList).AddRange(anotherList);

Đây không phải là thực hành tốt (xem bình luận dưới đây), như là một IList<T>sức mạnh không thể là một List<T>, nhưng một số loại khác mà thực hiện giao diện và có thể rất sẽ không có một AddRangephương pháp - trong trường hợp này, bạn sẽ chỉ tìm hiểu khi mã của bạn ném một ngoại lệ trong thời gian chạy.

Vì vậy, trừ khi bạn biết chắc chắn rằng loại thực sự là loại List<T>bạn không nên cố gắng sử dụng AddRange.

Một cách để làm như vậy là kiểm tra kiểu với toán tử is hoặc as (kể từ C # 7).

if(myIList is List<T>)
{
   // can cast and AddRange
}
else
{
   // iterate with Add
}

2
@ mohsen.d - Nếu kiểu được tạo, bạn không muốn thay đổi mã đã tạo (vì nó có thể bị ghi đè). ConcatTruyền hoặc sử dụng LINQ , như @Self_Taught_Programmer đã trả lời .
Đưa vào

2
@ mohsen.d - Nếu đó là mã của bạn, cũng có thể khai báo kiểu là List<T>(hoặc, nếu đây không phải là lựa chọn tốt cho bạn, hãy truyền diễn viên ở nơi bạn cần để AddRangebản địa hóa - đó là một hoạt động chi phí rất thấp ).
Đưa vào

53
Không không không. Lý do đây là một IList <T> để bắt đầu là vì nó có thể là một cái gì đó khác hơn là một triển khai Danh sách <T>. Viết một phương thức mở rộng như được hiển thị bởi BlackjacketMack nếu bạn thực sự cần một phương thức AddRange.
Derek Greer

6
Không hiểu tại sao điều này lại nhận được rất nhiều phiếu tán thành vì nó rõ ràng sẽ ném một thứ gì đó giống như InvalidCastExceptionđược sử dụng trên bất kỳ thứ gì khác ngoài List<T>(ví dụ: mảng).
bashis

3
Nhưng, casting không phải là một ý kiến ​​hay. Nó có thể dẫn đến chi phí hiệu suất.
Gul Md Ershad

77

Nếu bạn nhìn vào mã nguồn c # cho List , tôi nghĩ rằng List.AddRange () có những tối ưu hóa mà một vòng lặp đơn giản không giải quyết được. Vì vậy, một phương thức mở rộng chỉ cần kiểm tra xem IList có phải là một Danh sách hay không và nếu có thì hãy sử dụng AddRange () gốc của nó.

Nhìn xung quanh mã nguồn, bạn thấy những người .NET làm những việc tương tự trong phần mở rộng Linq của riêng họ cho những thứ như .ToList () (nếu đó là một danh sách, hãy truyền nó ... nếu không hãy tạo nó).

public static class IListExtension
{
    public static void AddRange<T>(this IList<T> list, IEnumerable<T> items)
    {
        if (list == null) throw new ArgumentNullException(nameof(list));
        if (items == null) throw new ArgumentNullException(nameof(items));

        if (list is List<T> asList)
        {
            asList.AddRange(items);
        }
        else
        {
            foreach (var item in items)
            {
                list.Add(item);
            }
        }
    }
}

5
Từ quan điểm tối ưu hóa, bạn thực sự đang truyền listđến List<T>hai lần ở đây. Một trong số đó có thể được tối ưu hóa với astừ khóa.
bashis

Gọi tốt @bashis. Tôi luôn quay đi quay lại về chi phí của một lần cast đôi so với việc dọn dẹp GC của var mới của chúng tôi. Nhưng chúng tôi thực sự có thể thực hiện var listCasted = list dưới dạng List <T>; if (! listCasted = null) ... Có lẽ c # 6 biểu khai sẽ thay đổi mô hình này: if (myVar.As (trong myVarCasted)) myVarCasted ...)
BlackjacketMack

Bạn có thể cập nhật mã với tối ưu hóa được đề cập không? Tôi không thông thạo các tính năng mới nhất. @BlackjacketMack

2
@zuckerthoben - Tôi vừa chạy thử nghiệm lặp lại một triệu lần lặp lại bằng cách sử dụng cả hai phương pháp và không có sự khác biệt về hiệu suất. Vì vậy, tôi sẽ không gọi nó là tối ưu hóa ... ngoài ra, nó thêm một dòng mã (nhưng làm giảm quá trình truyền parens). Nhưng dù sao, tôi có thể sẽ sử dụng 'as' những ngày này: var listCasted = list as List <T>; if (listCasted! = null) {listCasted.AddRange (items);}. Không đáng để cập nhật câu trả lời IMHO, nhưng tốt để giới thiệu như một phương án thay thế cú pháp.
BlackjacketMack

2
Tính đến bây giờ bạn có thể làmif (list is List<T> castedList) { castedList.AddRange(items); }
André Mantas

23

Bạn có thể làm điều gì đó như sau:

IList<string> oIList1 = new List<string>{"1","2","3"};
IList<string> oIList2 = new List<string>{"4","5","6"};
IList<string> oIList3 = oIList1.Concat(oIList2).ToList();

Vì vậy, về cơ bản bạn sẽ sử dụng Concat()tiện ích mở rộng và ToList()để có được một chức năng tương tự như AddRange().

Nguồn


1
Vấn đề với cách tiếp cận của bạn là nó Enumerable.Concatđược triển khai bởi System.Linq.Enumerablevà giá trị trả về của phương thức đó IEnumerable<TSource>, vì vậy tôi tin rằng nó không nên được chuyển trở lại IList<TSource>- nó có thể trả về thứ gì đó khác do chi tiết triển khai mà chúng tôi không biết nếu không kiểm tra mã nguồn - mặc dù vậy, không có gì đảm bảo rằng nó sẽ không thay đổi - vì vậy cần đặc biệt chú ý khi hỗ trợ nhiều phiên bản .NET.
jweyrich

8

Bạn cũng có thể viết một phương thức mở rộng như sau:

internal static class EnumerableHelpers
{
    public static void AddRange<T>(this IList<T> collection, IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            collection.Add(item);
        }
    }
}

Sử dụng:

        IList<int> collection = new int[10]; //Or any other IList
        var items = new[] {1, 4, 5, 6, 7};
        collection.AddRange(items);

Cái này vẫn đang lặp lại các mục, nhưng bạn không phải viết lần lặp hoặc ép kiểu mỗi khi bạn gọi nó.


1

Một câu trả lời khác sử dụng LINQ, miễn là thứ bạn đang thêm là một List<T>hoặc bạn có thể gọi ToList()nó:

IEnumerable<string> toAdd = new string[] {"a", "b", "c"};
IList<string> target = new List<string>();

toAdd.ToList().ForEach(target.Add);

-2
var var1 = output.listDepartment1
var var2 = output.listDepartment2  
var1.AddRange(var2);
var list = var1;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.