So fügen Sie der IList-Variablen eine Reihe von Elementen hinzu

81

Es gibt keine AddRange()Methode für IList<T>.

Wie kann ich eine Liste von Elementen zu einem hinzufügen, IList<T>ohne Elemente zu durchlaufen und die Add()Methode zu verwenden?

Mohsen Dorparasti
quelle

Antworten:

66

AddRangeist auf definiert List<T>, nicht die Schnittstelle.

Sie können die Variable als List<T>anstelle von deklarieren IList<T>oder List<T>in umwandeln, um Zugriff auf zu erhalten AddRange.

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

Dies ist keine gute Vorgehensweise (siehe Kommentare unten), da es sich IList<T>möglicherweise nicht um einen handelt List<T>, sondern um einen anderen Typ, der die Schnittstelle implementiert hat und möglicherweise keine AddRangeMethode hat. In diesem Fall werden Sie nur herausfinden, wann Ihr Code eine auslöst Ausnahme zur Laufzeit.

Wenn Sie also nicht sicher sind, dass der Typ tatsächlich ein Typ ist List<T>, sollten Sie nicht versuchen, ihn zu verwenden AddRange.

Eine Möglichkeit besteht darin, den Typ mit den Operatoren is oder as zu testen (seit C # 7).

if(myIList is List<T>)
{
   // can cast and AddRange
}
else
{
   // iterate with Add
}
Oded
quelle
2
@ mohsen.d - Wenn der Typ generiert wird, möchten Sie den generierten Code nicht ändern (da er möglicherweise überschrieben wird). Entweder Cast oder LINQ verwenden Concat, wie @Self_Taught_Programmer antwortete .
Oded
2
@ mohsen.d - Wenn es sich um Ihren Code handelt, können Sie den Typ auch als deklarieren List<T>(oder, wenn dies für Sie keine gute Wahl ist, die Besetzung dort durchführen, wo Sie AddRangesie lokalisieren müssen - dies ist eine sehr kostengünstige Operation ).
Oded
53
Nein nein Nein. Der Grund, warum dies zunächst eine IList <T> ist, liegt darin, dass es sich möglicherweise um etwas anderes als eine List <T> -Implementierung handelt. Schreiben Sie eine Erweiterungsmethode wie von BlackjacketMack gezeigt, wenn Sie wirklich eine AddRange-Methode benötigen.
Derek Greer
6
Keine Ahnung, warum dies so viele positive Stimmen erhalten hat, dass es eindeutig so etwas wie InvalidCastExceptionbei etwas anderem als List<T>(z. B. Array) auslöst .
Bashis
3
Casting ist jedoch keine gute Idee. Dies kann zu Leistungsaufwand führen.
Gul Md Ershad
78

Wenn Sie sich den c # -Quellcode für List ansehen, hat List.AddRange () Optimierungen, die eine einfache Schleife nicht adressiert. Eine Erweiterungsmethode sollte daher einfach überprüfen, ob die IList eine Liste ist, und in diesem Fall die native AddRange () verwenden.

Beim Stöbern im Quellcode sehen Sie, dass die .NET-Leute ähnliche Dinge in ihren eigenen Linq-Erweiterungen für Dinge wie .ToList () tun (wenn es sich um eine Liste handelt, setzen Sie sie um ... andernfalls erstellen Sie sie).

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);
            }
        }
    }
}
BlackjacketMack
quelle
5
Von der Optimierung Sicht werfen Sie eigentlich listzu List<T>zwei Mal hier. Eines davon könnte mit dem asSchlüsselwort optimiert werden .
Bashis
Guter Anruf @bashis. Ich gehe immer auf die Kosten einer Doppelbesetzung gegen GC-Bereinigung unserer neuen Var hin und her. Aber wir könnten tatsächlich var listCasted = list als List <T> machen; if (listCasted! = null) ... Vielleicht ändern c # 6-Deklarationsausdrücke dieses Muster: if (myVar.As (out myVarCasted)) myVarCasted ...)
BlackjacketMack
Können Sie den Code mit der genannten Optimierung aktualisieren? Ich bin noch nicht so fließend in den neuesten Funktionen. @ BlackjacketMack
2
@zuckerthoben - Ich habe gerade einen Test durchgeführt, bei dem eine Million Iterationen mit beiden Ansätzen wiederholt wurden, und es gab keinen Unterschied in der Leistung. Ich würde es also nicht als Optimierung bezeichnen ... zusätzlich wird eine Codezeile hinzugefügt (aber das Parens-Casting wird reduziert). Jedenfalls würde ich heutzutage wahrscheinlich 'als' verwenden: var listCasted = Liste als Liste <T>; if (listCasted! = null) {listCasted.AddRange (items);}. Es lohnt sich meiner Meinung nach nicht, die Antwort zu aktualisieren, aber es ist gut, sie als syntaktische Alternative einzuführen.
BlackjacketMack
2
Ab sofort können Sie tunif (list is List<T> castedList) { castedList.AddRange(items); }
André Mantas
23

Sie könnten so etwas tun:

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();

Im Grunde genommen würden Sie also die Concat()Erweiterung verwenden und ToList()eine ähnliche Funktionalität wie erhalten AddRange().

Quelle

Rayshawn
quelle
1
Das Problem bei Ihrem Ansatz besteht darin, dass er Enumerable.Concatimplementiert wird System.Linq.Enumerableund der Rückgabewert dieser Methode lautet IEnumerable<TSource>. Daher sollte er meines Erachtens nicht zurückgesetzt werden. IList<TSource>Aufgrund von Implementierungsdetails, die wir nicht kennen, ohne den Quellcode zu überprüfen, wird möglicherweise etwas anderes zurückgegeben. Es gibt jedoch keine Garantie dafür, dass sich nichts ändert. Daher muss bei der Unterstützung mehrerer .NET-Versionen besondere Aufmerksamkeit geschenkt werden.
Jweyrich
8

Sie können auch eine Erweiterungsmethode wie die folgende schreiben:

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

Verwendung:

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

Was immer noch über Elemente iteriert, aber Sie müssen die Iteration nicht jedes Mal schreiben oder umwandeln, wenn Sie sie aufrufen.

bashis
quelle
1

Eine andere Antwort mit LINQ, vorausgesetzt, Sie fügen eine hinzu List<T>oder können sie aufrufen ToList():

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

toAdd.ToList().ForEach(target.Add);
Roter Regen
quelle
-2
var var1 = output.listDepartment1
var var2 = output.listDepartment2  
var1.AddRange(var2);
var list = var1;
Siva Ragu
quelle