Как скопировать экземпляр объекта?

Я пытаюсь написать код, который заполняет List (на самом деле это серия Lists, но мы можем притворяться только одним List). Идея состоит в том, чтобы добавить IPackage в List для общего количества IPackage по порядку. См. Следующий код:

        ParseExcel pe = new ParseExcel();
        Pinnacle p = pe.ParsePinnacleExcel();
        Rack r = new Rack(20,2,4.5,96,42,6,25*12);
        foreach (PinnacleStock ps in p.StockList.Where(x => 
                 x.ColorCode == "10" && 
                 x.PackageLength == 30.64))
        {
            for (int i = 1; i <= ps.OnOrder; i++)
            {
                r.TryAddPackage((IPackage)ps);
            }
        }

Кажется, что все работает хорошо, поскольку IPackage неоднократно добавляется в список. Однако кажется, что тот же экземпляр объекта добавляется, т.е. Объект не копируется каждый раз, когда он добавляется в список.

Что мне нужно сделать, чтобы убедиться, что в список вставляется копия объекта, а не только дополнительная ссылка?

Ответы

Ответ 1

Затем вам нужно реализовать ICloneable и заменить

r.TryAddPackage((IPackage)ps);

с

r.TryAddPackage((IPackage)ps.Clone());

Вам решать, как Clone заполнить новый экземпляр PinnacleStock, который он возвращает.

На самом базовом уровне вы можете сказать

public PinnacleStock : ICloneable {
    public PinnacleStock Clone() {
        return (PinnacleStock)this.MemberwiseClone();
    }
    object ICloneable.Clone() {
        return Clone();
    }
    // details
}

Это будет делать мелкую копию PinnacleStock. Только вы знаете, является ли это правильной семантикой для вашего домена.

Ответ 2

Если вам нужна только мелкая копия, вы можете написать метод быстрого клонирования:

public class PinnacleStock : ICloneable
{
    public PinnacleStock Clone()
    {
        return (PinnacleStock)this.MemberwiseClone();
    }

    object ICloneable.Clone()
    {
        return Clone();
    }

    // Other methods
}

Если вам нужна глубокая копия (т.е. если PinnacleStock есть под-объекты, которые вы хотите скопировать), тогда вам нужно будет написать их самостоятельно.

Ответ 3

Как говорили другие, вам нужно будет сделать эту копию в определенном способе PinnacleStock:

foreach (PinnacleStock ps in p.StockList.Where(x => x.ColorCode == "10" && 
                                                    x.PackageLength == 30.64))
{
  for (int i = 1; i <= ps.OnOrder; i++)
  {
    PinnacleStock clone = ps.CopySomehow();  // your problem
    r.TryAddPackage((IPackage)clone);
  }
}

Однако вы можете задать вопрос, является ли это правильным решением. Вам действительно нужен отдельный экземпляр PinnacleStock? Добавляет ли PinnacleStock к стойке действительно новый, независимый экземпляр? Планируете ли вы отдельно модифицировать или отслеживать каждую из этих отдельных копий? Правильно ли, что теперь у вас будут экземпляры PinnacleStock, которые не отображаются в вашем StockList? Не зная ваш домен или семантику PinnacleStock, трудно быть уверенным, но, возможно, вы захотите рассмотреть, например, создание объекта PinnacleStockRackEntry для представления экземпляра PinnacleStock - конечно, зависит от предполагаемой семантики!

Ответ 4

Вы должны предоставить логику для копирования объекта самостоятельно..Net не имеет встроенного в глубокую копию встроенного (с заметным потенциальным исключением сериализации). Ближе всего это метод MemberwiseClone(), но даже это будет копировать ссылки для любых членов вашего типа, которые сами являются ссылочным типом.