Значения коллекции, изменяющиеся в цикле - PullRequest
1 голос
/ 06 июня 2009

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

ArrayList CaseRecordItems = new ArrayList(); // this is created earlier
string baseTif = "sometext_"; // this is created earlier
CaseRecord cr = new CaseRecord(); (this gets populated with "stuff")
char increment = 'A';

for (int i = 0; i < FirstNames.Count; i++)
{
    cr.Firstname = (string)FirstNames[i];
    cr.Lastname = (string)LastNames[i];
    if (FirstNames.Count > 1)
    {
        cr.Tif = baseTif + increment.ToString();
        increment++;
    }
    CaseRecordItems.Add(cr);
}

Цикл выполняется, например, два раза и должен установить значение cr.Tif равным sometext_A и sometext_B. Это работает правильно, но как только второй элемент добавляется в коллекцию, значение первого изменяется в соответствии с ним.

Я подозреваю, что это из-за недостатка моего понимания того, как эти объекты создаются и распространяются. Любое понимание будет оценено.

EDIT:

На основании потрясающей обратной связи (и моего оцепенения) проблема была решена. Благодаря ответу Дэна я сделал несколько изменений в коде, который я пробовал, прежде чем использовать функцию клона (да, Бич, я действительно пробовал это: P).

Новый блок выглядит так: ArrayList CaseRecordItems = new ArrayList (); // это создано ранее string baseTif = "sometext_"; // это создано ранее CaseRecord cr = new CaseRecord (); // это заполняется "материалом") приращение символа = 'A';

for (int i = 0; i < FirstNames.Count; i++)
{
    CaseRecord cr2 = new CaseRecord();
    cr2 = cr.Clone();                        // preserves the data from outside
    cr2.Firstname = (string)FirstNames[i];
    cr2.Lastname = (string)LastNames[i];
    if (FirstNames.Count > 1)
    {
        cr2.Tif = baseTif + increment.ToString();
        increment++;
    }
    CaseRecordItems.Add(cr2);
}

Спасибо всем за супер-быстрые ответы!

Ответы [ 7 ]

7 голосов
/ 06 июня 2009

Я предполагаю, что cr - это объект. Вы не создаете новый cr каждый раз, поэтому у вас есть одна и та же ссылка в массиве списков дважды, поэтому, когда вы изменяете его во второй раз, вы фактически работаете над одним и тем же объектом.

2 голосов
/ 06 июня 2009

Вы изменяете значение экземпляра cr внутри цикла. Каждая итерация цикла использует один и тот же экземпляр cr, поэтому при его изменении все они изменяются. Чтобы решить эту проблему, соответствующий метод должен использовать локальный экземпляр внутри цикла:

for (int i = 0; i < FirstNames.Count; i++)
{
    CaseRecord cr=new CaseRecord();

    ...

    CaseRecordItems.Add(cr);
}
1 голос
/ 06 июня 2009

Есть ли у объекта cr функция клонирования?

Если это так, это должно сделать это:

CaseRecordItems.Add(cr.Clone());
1 голос
/ 06 июня 2009

Проблема в том, что переменная cr одинакова оба раза в цикле, поэтому оба раза в цикле изменяется один и тот же объект и один и тот же объект добавляется в ArrayList дважды.

Вы не показываете достаточно кода, чтобы показать, где объявлен cr.

Вам нужно сделать что-то вроде

for (int i = 0; i < FirstNames.Count; i++)
{
    CRObject cr = new CRObject();

    cr.Firstname = (string)FirstNames[i];
    cr.Lastname = (string)LastNames[i];
    if (FirstNames.Count > 1)
    {
        cr.Tif = baseTif + increment.ToString();
        increment++;
    }
    CaseRecordItems.Add(cr);
}
0 голосов
/ 06 июня 2009

Предполагая, что cr является классом, вам нужно будет создавать новый экземпляр класса при каждом прохождении цикла, например cr = new crClassName ();

Причина в том, что в CaseRecordItems добавляется указатель на объект, а не его копия, поэтому при изменении его на втором проходе, по-видимому, изменяется и первое значение.

0 голосов
/ 06 июня 2009

Если вы не создаете cr (каким бы он ни был) внутри цикла for, то вы модифицируете один и тот же объект, снова и снова, каждый раз в цикле. Вы хотите создать новый экземпляр cr внутри цикла for.

0 голосов
/ 06 июня 2009

Поскольку cr не получает новое утверждение (я не знаю тип cr, или я бы показал вам), вы просто добавляете одну и ту же ссылку снова и снова. Если вы хотите добавить новые элементы cr в CaseRecordItems, вы начинаете делать cr = new TypeOfCR (); в противном случае вы просто перезаписываете один и тот же объект снова и снова.

РЕДАКТИРОВАТЬ: Не забудьте сделать новый внутри вашего цикла

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...