Копировать элементы ref-type структуры по значению

У меня есть структура и класс

public class MyClass
{
    public string name;
}

public struct MyStructure
{
    public MyClass classValue;
    public int intValue;
    public MyStructure(MyClass classValue, int intValue)
    {
        this.classValue = classValue;
        this.intValue = intValue;
    }
}

В другом месте я пишу следующий код:

MyClass class1 = new MyClass() { name = "AA" };
MyStructure struct1 = new MyStructure(class1, 4);
MyStructure struct2 = struct1;
struct1.classValue.name = "BB";  //struct2.classValue.name also change!

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


person Hossein Narimani Rad    schedule 22.01.2013    source источник
comment
struct не был хорошим выбором для myStructure. Это корень проблемы.   -  person Henk Holterman    schedule 22.01.2013
comment
@HenkHolterman прав. Зачем вам нужна семантика struct для этого? Есть веские причины использовать struct, но ситуации очень специфичны.   -  person Chris Pfohl    schedule 22.01.2013
comment
См. также stackoverflow.com/questions /11336935/   -  person 500 - Internal Server Error    schedule 22.01.2013
comment
@HenkHolterman Может быть, вам следует объяснить, почему вы не думаете, что MyStructure должен быть struct. Он состоит из одной ссылки на объект и одного Int32. Как написано, это изменяемый struct, но это не относится к вопросу. Его можно было бы сделать неизменяемым. Такое же поведение будет найдено для KeyValuePair<int, MyClass>, который является struct.   -  person Jeppe Stig Nielsen    schedule 22.01.2013
comment
@ChristopherPfohl Поможет ли ему переход на class? Нет. Кажется, ему нужна глубокая копия, а struct не дает ему этого. Класс даже не дает ему неглубокую копию (он просто дает новую ссылку на тот же объект), поэтому на самом деле это не ближе к тому, что он хочет. Похоже, он выбрал struct, потому что хотел использовать семантику копирования по значению. Это веская причина для выбора struct.   -  person Jeppe Stig Nielsen    schedule 22.01.2013


Ответы (2)


Ваш MyStructure состоит из ссылки на объект типа MyClass и int (Int32). Назначение

MyStructure struct2 = struct1;

копирует только эти данные, ссылку и целое число. Новый экземпляр MyClass не создается. Вы не можете изменить это.

Если вы хотите скопировать, вы можете сказать

MyStructure struct2 = new MyStructure(
    new MyClass { name = struct1.classValue, },
    struct1.intValue
    );

Конечно, если вам нужно делать это часто, вы можете написать метод Clone(), который будет делать именно это. Но вам нужно будет не забыть использовать метод Clone, а не просто присваивать.

(Кстати, MyStructure — это «изменяемая структура». Многие люди не одобряют их. Если вы пометите поля MyStructure как readonly, я думаю, что «многие люди» будут довольны.)

Дополнение. См. также Ответ на Могут ли структуры содержать ссылки на ссылочные типы в C#< /а>.

person Jeppe Stig Nielsen    schedule 22.01.2013
comment
Гораздо менее опасно для структуры иметь поля, допускающие кусочную мутацию, чем для структуры инкапсулировать состояние в объекты, которые могут быть изменены. Для структуры нормально иметь идентификацию изменяемого объекта класса как часть своего состояния (как в случае, например, со структурами KeyValuePair<string, Form>, которые инкапсулируют состояние изменяемого объекта как часть своего состояния). собственное состояние, как правило, имеет очень запутанную семантику. - person supercat; 10.02.2013

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

public MyStructure(MyStructure structure)
{
    classValue = new MyClass() { name = structure.classValue.name };
    intValue = structure.intValue;
}

Затем вызовите конструктор копирования, используя:

MyStructure struct2 = new MyStructure(struct1);

В качестве альтернативы вы можете изменить MyClass на структуру.

person Brett Wolfington    schedule 22.01.2013
comment
Я также думал об изменении MyClass на структуру. Но похоже, что ему нужно мутировать MyClass экземпляров, поэтому превращение его в struct приведет к изменяемой структуре, которую многие люди считают злом. - person Jeppe Stig Nielsen; 23.01.2013
comment
Структуры, вложенные в структуры изменяемого открытого поля, прекрасно работают; с точки зрения производительности к полям внутренней структуры можно обращаться, как если бы они были просто полями внешней структуры. Структуры, которые инкапсулированы как свойства других типов или поля только для чтения, работают хуже, система должна будет сделать избыточную копию таких структур для доступа к любым их свойствам. - person supercat; 11.02.2013