Добавление элемента в IEnumerable - PullRequest
6 голосов
/ 17 февраля 2011

У меня был список <> моих объектов, но теперь нужно изменить его на IEnumerable <>. Итак, у меня есть это:

public IEnumerable<TransactionSplitLine> TransactionSplitLines { get; set; }

Однако я больше не могу:

reply.TransactionSplitLines.Add(new TransactionSplitLine
                                                    {Amount = "100", Category = "Test", SubCategory = "Test More", CategoryId=int.Parse(c)});

Как мне теперь добавлять предметы?

Ответы [ 8 ]

19 голосов
/ 17 февраля 2011

Вы можете сделать что-то вроде следующего, используя Concat:

reply.TransactionSplitLines = 
    reply.TransactionSplitLines.Concat(new []{new TransactionSplitLine                                                     {
                                                 Amount = "100", 
                                                 Category = "Test", 
                                                 SubCategory = "Test More",
                                                 CategoryId = int.Parse(c)}});

Это в основном создает новый IEnumerable.Трудно сказать, каково лучшее решение в вашем случае, поскольку недостаточно информации о вашем случае использования.

РЕДАКТИРОВАТЬ: Обратите внимание, что List<T> реализуетIEnumerable<T>.Поэтому, если вам нужно передать IEnumerable<T> в качестве параметра, например, вы также можете вместо этого передать List<T>, возможно, сначала явно вызвав AsEnumerable() в вашем списке.Поэтому, возможно, вы могли бы придерживаться списка вместо IEnumerable.

9 голосов
/ 17 февраля 2011

Краткий ответ: Вы не можете добавлять элементы в IEnumerable<T>

Чуть более длинное объяснение:

IEnumerable - это интерфейс, который заботится исключительно о возможности перечисления / перебора коллекции элементов. Это единственная цель существования IEnumerable. Он абстрагирует любое представление о способе хранения или извлечения перечислимых элементов (это может быть строка символов, список элементов, поток байтов или ряд результатов вычислений), таким образом, если у вас есть интерфейс, который является IEnumerable, вы не можете добавлять элементы к нему, вы можете перебирать только те элементы, которые он предоставляет.

Тем не менее, правильный способ добавить элементы в IEnumerable - это вернуть новый IEnumerable с новыми элементами, добавленными к содержимому оригинала.

Также с библиотеками Linq у вас есть метод расширения, который позволяет преобразовывать ваш IEnumerable в список с помощью IEnumerable.ToList(), и вы можете добавлять элементы в список. Это не может быть правильным способом.

С библиотеками Linq в вашем пространстве имен вы можете делать следующее:

using System;
using System.Collections.Generic;
using System.Linq;

namespace EnumTester
{
    class Program
    {
        static void Main(string[] args)
        {
             IEnumerable<string> enum = GetObjectEnumerable();

             IEnumerable<string> concatenated = enum.Concat(new List<string> { "concatenated" });

             List<string> stringList = concatenated.ToList();
        }
    }
}
5 голосов
/ 17 февраля 2011

Вы не можете добавлять элементы в IEnumerable<T>, так как у этого интерфейса нет метода Add.
если TransactionSplitLines всегда возвращает экземпляр List<TransactionSplitLine>, вы можете изменить его тип на IList<TransactionSplitLine>.
Если вы не можете изменить тип TransactionSplitLines и можете гарантировать, что он всегда возвращает IList<TransactionSplitLines>, вы можете разыграть его как в

((IList<TransactionSplitLine>)reply.TransactionSplitLines).Add(new TransactionSplitLine
                                                    {Amount = "100", Category = "Test", SubCategory = "Test More", CategoryId=int.Parse(c)});
3 голосов
/ 17 февраля 2011

IEnumerable<T> не имеет метода Add(T).В зависимости от вашего реального типа, вы можете разыграть его следующим образом:

var item = new TransactionSplitLine {Amount = "100", Category = "Test", SubCategory = "Test More", CategoryId=int.Parse(c)};

((IList)reply.TransactionSplitLines).Add(item);

Если используемая коллекция реализует IList.

Помните, что вы хотитеИспользуйте самый простой интерфейс / класс, когда вы передаете свои объекты.Поэтому, если вам нужно использовать методы из IList, я бы предложил вам использовать это вместо IEnumerable.

. Я бы предложил вам сделать следующее Изменение:

public IList<TransactionSplitLine> TransactionSplitLines { get; set; }
2 голосов
/ 17 февраля 2013

Я бы создал этот метод расширения, который делает все это лениво:

public static IEnumerable<T> Append<T>(this IEnumerable<T> source, params T[] items)
{
    return source.Concat(items);
}

Так что в вашем случае:

var item = new TransactionSplitLine { Amount = "100", Category = "Test", 
                                      SubCategory = "Test More", 
                                      CategoryId = int.Parse(c) };
reply.TransactionSplitLines.Append(item);

Вы также можете иметь Prepend также:

public static IEnumerable<T> Prepend<T>(this IEnumerable<T> source, params T[] items)
{
    return items.Concat(source);
}
2 голосов
/ 17 февраля 2011

Это зависит от того, каков смысл и назначение вашего свойства TransactionSplitLines.

Если вы хотите разрешить редактирование (добавление / удаление) извне вашего класса, просто сделайте ваше свойство менее универсальнымчем IEnumerable<T> например:

public IList<TransactionSplitLine> TransactionSplitLines { get; set; }

или лучше:

public ICollection<TransactionSplitLine> TransactionSplitLines { get; set; }

Вместо этого, если вам нужно просто отредактировать коллекцию внутри (я имею в виду в области видимости класса)почему бы вам не сделать что-то вроде этого:

private List<TransactionSplitLine> transactionSplitLines;

public IEnumerable<TransactionSplitLine> TransactionSplitLines 
{ 
  get
  {
     return transactionSplitLines;
  }
}

, чтобы вы могли использовать поле transactionSplitLines для внутреннего изменения коллекции.

0 голосов
/ 06 февраля 2018

IEnumerable является неизменяемой коллекцией, это означает, что вы не можете добавлять или удалять элементы. Метод расширения создает новый экземпляр. (Объясняется, например, здесь: Какой лучший способ добавить один элемент в IEnumerable ? ) Скорее, создав метод Extension, можно изначально добавить его в список, как показано ниже: Например, в моем случае роли пользователей определены как IEnumerable (в классе модели User). Итак, чтобы добавить значение этой роли. Изначально я определил список:

List<Role> rols=new List<Role>();

Внутри цикла добавило значение этому списку, например:

foreach(int i=0;i<chkRoles.count;i++)
{
 Role r=new Role();
r.RoleId="2";
r.RoleName="Admin";
rols.add(r);
}

и затем передайте это значение IEnumerable ist:

user.Roles=rols.AsEnumerable();
0 голосов
/ 17 февраля 2011

Вы можете использовать метод Concat для объединения двух таких наборов:

reply.TransactionSplitlines = reply.TransactionSplitlines.Concat(/* another enumerable */);

Вам нужно написать метод расширения AsEnumerable, который бы взял obj и сделал бы что-то вроде yield return obj;. Вы можете избежать написания метода расширения и просто передать new [] с объектом в нем методу Concat, но если ваш интерфейс основан на IEnumerable, вполне вероятно, что вам понадобится метод AsEnumerable в некоторых другие случаи тоже.

Это если вам действительно нужно, чтобы это было IEnumerable. Однако я бы посоветовал перейти на IList<T> или другой интерфейс, поддерживающий add. Если вам нужно реализовать какой-либо интерфейс с помощью свойства IEnumerable<>, вы можете иметь IList<> в качестве внутреннего поля для этого свойства и изменять его отдельно - есть вероятность, что вы работаете здесь с конкретным объектом, а не с интерфейсом. Если вы работаете с интерфейсом и по-прежнему должны использовать Add, IEnumerable<> - просто плохой выбор типа для этого интерфейса.

...