Невозможно добавить элементы в список IList / List, добавляемый из IEnumerable - PullRequest
0 голосов
/ 19 апреля 2011

Я пытаюсь создать небольшое тестовое приложение для моего босса, однако созданный мной код, имитирующий то, что он пытается осуществить, не работает.

for (int i = 0; i < 5000; i++)
{
     ((IList<string>) obj2.Stuff).Add("Iteration " + i.ToString());
}

Я пытаюсь осуществить все это в одной строке, потому что именно так его код выглядел на днях в фреймворке, над которым мы работаем.В любом случае, когда приведенный выше код выполняется, я получаю сообщение об ошибке во время выполнения, в котором говорится, что «Коллекция была фиксированного размера».И когда я пытаюсь привести к списку вместо IList, я получаю InvalidCastException, говорящую «Невозможно привести объект типа 'System.String []' к типу System.Collections.Generic.List`1 [System.String] '. "

У кого-нибудь есть идеи, как я могу выполнить однострочное приведение, чтобы добавить элемент в IEnumerable или помочь мне найти способ обойти две ошибки, которые я продолжаю получать?Заранее спасибо.

РЕДАКТИРОВАТЬ (19.04.2011 10:49 EST) Я добавляю больше кода, чтобы помочь людям - вероятно, следовало бы сделать это раньше.Извините.

Program.cs:

        #region Cast Test
        Class1 obj2 = new Class1();
        obj2.Stuff = Enumerable.Empty<string>();

        Console.WriteLine("Cast - Start Time: " + 0 + "ms");

        Stopwatch stopwatch2 = new Stopwatch();
        stopwatch.Start();

        for (int i = 0; i < 5000; i++)
        {
            ((IList<string>) obj2.Stuff).Add("Iteration " + i.ToString());
        }

        stopwatch2.Stop();
        Console.WriteLine("Cast - Stop Time: " + stopwatch2.ElapsedMilliseconds.ToString() + "ms");
        #endregion

Class1.cs:

public class Class1
{
    private IEnumerable<string> stuff;

    public IEnumerable<string> Stuff
    {
        get { return stuff; }
        set { stuff = value; }
    }
}

Ответы [ 9 ]

2 голосов
/ 19 апреля 2011

Вы не можете привести string[] к IList<string>, поскольку string[] не реализует этот интерфейс. Сначала вам нужно будет создать объект, реализующий IList<string>:

List<string> list = obj2.Stuff.ToList();
for (int i = 0; i < 5000; i++)
{
     list.Add("Iteration " + i.ToString());
}
2 голосов
/ 19 апреля 2011

Массивы в C # имеют фиксированный размер. Вы не можете добавлять предметы к ним.

1 голос
/ 19 апреля 2011

Зачем бросать внутри для цикла?В то время как каждый IList является IEnumerable, не каждый IEist является IList.Вы можете использовать метод расширения ToList, чтобы скопировать IEnumerable в новый список.(Просто убедитесь, что это using System.Linq;)

Кроме того, в этом примере нет необходимости в цикле for:

var list = obj2.Stuff.ToList();
new list.AddRange(Enumerable.Range(0, 5000).Select(i => "Iteration " + i.ToString()));
0 голосов
/ 19 апреля 2011

В комментариях к одному из ответов выше вы говорите: «Я пытаюсь избежать копирования списка».

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

Так что, чтобы использовать приведенный выше пример foson, вы можете просто сделать:

obj2.Stuff = Enumerable.Range(0, 5000).Select(i => "Iteration " + i.ToString());

Обратите внимание, что при выполнении этого кода на самом деле ничего не происходит .Никакие объекты не будут созданы, пока что-то фактически не повторяется по obj2.StuffКогда это произойдет, будут вызваны методы в LINQ, которые создают объекты по одному и возвращают их в цикл итератора.

Но здесь нет реального устройства хранения данных.Вы можете перебрать obj2.Stuff, и если вы не добавите каждое целое число к чему-то еще, они будут пропущены на следующей итерации.

Фундаментальный момент здесь - вы не можете хранить вещи в IEnumerable, а, IEnumerable - это способ возврата объектов в последовательности, который может быть из конструкции списка или из функции, которая генерирует последовательность.

0 голосов
/ 19 апреля 2011

Поскольку obj2.Stuff является строковым массивом, невозможно выполнить то, что вы пытаетесь сделать.Размер массива не может быть изменен, поэтому вы не можете добавлять в него элементы.

Если вы можете заменить массив в obj2.Stuff другим массивом, вы можете получить данные из массива и составить списокиз него добавьте элементы в список, получите данные из списка и создайте из него массив и используйте его для замены исходного массива:

List<string> items = new List<string>(obj2.Stuff);
for (int i = 0; i < 5000; i++) {
  items.Add("Iteration " + i.ToString());
}
obj2.Stuff = items.ToArray();

Если свойство obj2.Stuff доступно только для чтения, тогда вы не сможете ничего добавить к нему, пока не измените базовую реализацию из массива в коллекцию, в которую можно добавлять элементы.

0 голосов
/ 19 апреля 2011

Измените тип obj2.Stuff на что-то вроде StringCollection или List.В .NET массивы имеют фиксированную длину, и вы не можете добавлять в них новые объекты, поэтому используйте вместо них коллекции.

0 голосов
/ 19 апреля 2011

Тип System.String[] - это массив строк, который реализует IEnumerable<string>, но не a List<string>.Массивы имеют фиксированную длину.Зачем вам это нужно в одну строку?

0 голосов
/ 19 апреля 2011

Вы не можете вызвать Add, поскольку obj2.Stuff выглядит как массив, а массив имеет фиксированный размер, как указывает сообщение об ошибке.

0 голосов
/ 19 апреля 2011

IEnumerable не предоставляет вам те же функции, что и IList. Если ваш Stuff не является IEnumerable, который также является IList, ваш код не будет работать.

Контракт первого только обещает, что вы можете повторить его по одному элементу за раз. Никогда не говорится, что вы можете добавлять новые элементы.

Вы можете выполнить это только в том случае, если во время выполнения ваш перечисляемый объект также удовлетворяет интерфейсу IList.

...