no hay AddRange()
método para IList<T>
.
¿Cómo puedo agregar una lista de elementos a IList<T>
sin iterar a través de elementos y usar el Add()
método?
no hay AddRange()
método para IList<T>
.
¿Cómo puedo agregar una lista de elementos a IList<T>
sin iterar a través de elementos y usar el Add()
método?
Respuestas:
AddRange
se define en List<T>
, no la interfaz.
Puede declarar la variable como en List<T>
lugar de IList<T>
o convertirla List<T>
en para obtener acceso a AddRange
.
((List<myType>)myIList).AddRange(anotherList);
Esta no es una buena práctica (vea los comentarios a continuación), ya que IList<T>
puede que no sea un List<T>
, pero algún otro tipo que implementó la interfaz y puede que no tenga un AddRange
método; en tal caso, solo lo descubrirá cuando su código arroje un excepción en tiempo de ejecución.
Por lo tanto, a menos que sepa con certeza que el tipo es de hecho List<T>
, no debería intentar usarlo AddRange
.
Una forma de hacerlo es probando el tipo con los operadores is o como (desde C # 7).
if(myIList is List<T>)
{
// can cast and AddRange
}
else
{
// iterate with Add
}
List<T>
(o, si esta no es una buena opción para usted, hacer el reparto donde necesita AddRange
para mantenerlo localizado - es una operación de muy bajo costo ).
InvalidCastException
si se usa en cualquier otra cosa que no sea List<T>
(matriz, por ejemplo).
Si observa el código fuente de C # para List , creo que List.AddRange () tiene optimizaciones que un simple bucle no aborda. Por lo tanto, un método de extensión simplemente debe verificar si IList es una Lista, y si es así, use su AddRange () nativo.
Al hurgar en el código fuente, ve que la gente de .NET hace cosas similares en sus propias extensiones Linq para cosas como .ToList () (si es una lista, envíelo ... de lo contrario, créelo).
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);
}
}
}
}
list
a List<T>
dos veces aquí. Uno de los cuales podría optimizarse con la as
palabra clave.
if (list is List<T> castedList) { castedList.AddRange(items); }
Podrías hacer algo como esto:
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();
Entonces, básicamente, usaría la Concat()
extensión y ToList()
obtendría una funcionalidad similar a AddRange()
.
Enumerable.Concat
está implementado por System.Linq.Enumerable
y el valor de retorno de ese método es IEnumerable<TSource>
, por lo que creo que no debería devolverse IList<TSource>
, podría devolver algo más debido a los detalles de implementación que no conocemos sin verificar el código fuente. aunque no hay garantía de que no cambie, por lo que se debe prestar especial atención al admitir varias versiones.
También puede escribir un método de extensión como este:
internal static class EnumerableHelpers
{
public static void AddRange<T>(this IList<T> collection, IEnumerable<T> items)
{
foreach (var item in items)
{
collection.Add(item);
}
}
}
Uso:
IList<int> collection = new int[10]; //Or any other IList
var items = new[] {1, 4, 5, 6, 7};
collection.AddRange(items);
Que todavía está iterando sobre elementos, pero no tiene que escribir la iteración o lanzar cada vez que lo llama.
Otra respuesta usando LINQ, siempre que lo que está agregando sea un List<T>
o pueda llamarlo ToList()
:
IEnumerable<string> toAdd = new string[] {"a", "b", "c"};
IList<string> target = new List<string>();
toAdd.ToList().ForEach(target.Add);
Concat
Emite o usa LINQ , como respondió @Self_Taught_Programmer .