Pregunta

Mi pregunta como título arriba. Por ejemplo,

IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));

pero después de todo solo tiene 1 elemento adentro.

¿Podemos tener un método como items.Add (item) ?

como List<T>

¿Fue útil?

Solución

No puede, porque IEnumerable < T > no representa necesariamente una colección a la que se pueden agregar elementos. De hecho, ¡no representa necesariamente una colección en absoluto! Por ejemplo:

IEnumerable<string> ReadLines()
{
     string s;
     do
     {
          s = Console.ReadLine();
          yield return s;
     } while (s != "");
}

IEnumerable<string> lines = ReadLines();
lines.Add("foo") // so what is this supposed to do??

Sin embargo, lo que puede hacer es crear un objeto nuevo IEnumerable (de tipo no especificado) que, cuando se enumera, proporcionará todos los elementos del anterior, más algunos de los tuyos. Utiliza Enumerable.Concat para eso:

 items = items.Concat(new[] { "foo" });

Este no cambiará el objeto de matriz (de todos modos, no puede insertar elementos en las matrices). Pero creará un nuevo objeto que enumerará todos los elementos de la matriz y luego "Foo". Además, ese nuevo objeto hará un seguimiento de los cambios en la matriz (es decir, cada vez que lo enumere, verá los valores actuales de los elementos).

Otros consejos

El tipo IEnumerable < T > no admite tales operaciones. El propósito de la interfaz IEnumerable < T > es permitir que un consumidor vea el contenido de una colección. No modificar los valores.

Cuando realiza operaciones como .ToList (). Add () está creando una nueva List < T > y agrega un valor a esa lista. No tiene conexión con la lista original.

Lo que puede hacer es usar el método Agregar extensión para crear un nuevo IEnumerable < T > con el valor agregado.

items = items.Add("msg2");

Incluso en este caso no modificará el objeto original IEnumerable < T > . Esto se puede verificar manteniendo una referencia a él. Por ejemplo

var items = new string[]{"foo"};
var temp = items;
items = items.Add("bar");

Después de este conjunto de operaciones, la variable temp solo hará referencia a un enumerable con un solo elemento '' foo '' en el conjunto de valores, mientras que los elementos harán referencia a un enumerable diferente con valores "foo" y "bar".

EDIT

Siempre olvido que Agregar no es un método de extensión típico en IEnumerable < T > porque es uno de los primeros que termino definiendo. Aquí está

public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) {
  foreach ( var cur in e) {
    yield return cur;
  }
  yield return value;
}

¿Ha considerado usar ICollection < T > o IList < T > en cambio, existen por la razón por la que desea tener un método Add en un IEnumerable < T > .

IEnumerable < T > se usa para 'marcar' un tipo como ... bueno, enumerable o simplemente una secuencia de elementos sin garantizar necesariamente si el objeto subyacente real admite agregar / eliminación de artículos. Recuerde también que estas interfaces implementan IEnumerable < T > para que obtenga todos los métodos de extensiones que obtiene con IEnumerable < T > también.

Un par de métodos de extensión cortos y dulces en IEnumerable y IEnumerable < T > lo hacen por mí:

public static IEnumerable Append(this IEnumerable first, params object[] second)
{
    return first.OfType<object>().Concat(second);
}
public static IEnumerable<T> Append<T>(this IEnumerable<T> first, params T[] second)
{
    return first.Concat(second);
}   
public static IEnumerable Prepend(this IEnumerable first, params object[] second)
{
    return second.Concat(first.OfType<object>());
}
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, params T[] second)
{
    return second.Concat(first);
}

Elegante (bueno, excepto para las versiones no genéricas). Lástima que estos métodos no están en el BCL.

No, el IEnumerable no admite agregarle elementos.

Tu 'alternativa' es:

var List = new List(items);
List.Add(otherItem);

En .net Core, hay un método Enumerable.Append que hace exactamente eso.

El código fuente del método es disponible en GitHub. .... Vale la pena echarle un vistazo a la implementación (más sofisticada que las sugerencias en otras respuestas) :).

Para agregar un segundo mensaje necesita -

IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})

No solo no puede agregar elementos como dice, sino que si agrega un elemento a una List < T > (o prácticamente a cualquier otra colección que no sea de solo lectura) que tenga una enumerador para, el enumerador se invalida (arroja InvalidOperationException a partir de ese momento).

Si está agregando resultados de algún tipo de consulta de datos, puede usar el método de extensión Concat :

Editar: Originalmente usé la extensión Union en el ejemplo, lo cual no es realmente correcto. Mi aplicación lo utiliza ampliamente para asegurar que las consultas superpuestas no dupliquen los resultados.

IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);

Solo vengo aquí para decir que, aparte del método de extensión Enumerable.Concat , parece que hay otro método llamado Enumerable.Append en .NET Core 1.1.1 . Este último le permite concatenar un solo elemento a una secuencia existente. Entonces la respuesta de Aamol también se puede escribir como

IEnumerable<T> items = new T[]{new T("msg")};
items = items.Append(new T("msg2"));

Aún así, tenga en cuenta que esta función no cambiará la secuencia de entrada, solo devolverá un contenedor que juntará la secuencia dada y el elemento adjunto.

Otros ya han dado excelentes explicaciones sobre por qué no puedes (¡y no deberías!) poder agregar elementos a un IEnumerable . Solo agregaré que si desea continuar codificando en una interfaz que representa una colección y desea un método de agregar, debe codificar a ICollection o IList . Como bonanza adicional, estas interfaces implementan IEnumerable .

puedes hacer esto.

//Create IEnumerable    
IEnumerable<T> items = new T[]{new T("msg")};

//Convert to list.
List<T> list = items.ToList();

//Add new item to list.
list.add(new T("msg2"));

//Cast list to IEnumerable
items = (IEnumerable<T>)items;

La forma más fácil de hacerlo es simplemente

IEnumerable<T> items = new T[]{new T("msg")};
List<string> itemsList = new List<string>();
itemsList.AddRange(items.Select(y => y.ToString()));
itemsList.Add("msg2");

Entonces puede devolver la lista como IEnumerable también porque implementa la interfaz IEnumerable

Claro, puedes (estoy dejando de lado tu negocio T):

public IEnumerable<string> tryAdd(IEnumerable<string> items)
{
    List<string> list = items.ToList();
    string obj = "";
    list.Add(obj);

    return list.Select(i => i);
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top