В C#, каковы некоторые практические правила для _where_ для клонирования объектов?

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

У меня есть два варианта:

  • Клонируйте объект в вызывающем объекте и передайте клонированный объект методу ("вызываемый"), тем самым предотвращая потенциальную модификацию вызываемого объекта.
  • Клонируйте объект в вызываемом объекте, потому что вызываемый объект изменяет передаваемый объект, что делает предположение, что вызывающий объект никогда не хочет, чтобы объект аргумента был изменен.

Я нашел этот 6-летний ответ с различными мнениями. К сожалению, не похоже, что был настоящий консенсус.

Передача копии объекта в метод - кто делает копирование?

Вот мой вопрос в кодовой форме:

  • Должен ли я клонировать объект в вызывающей программе и передать клонированный объект методу?
public static void Main()
{
    var foo = new Foo();
    Bar.Baz(foo.DeepClone());
}

public static class Bar
{
    public static void Baz(Foo foo)
    {
        /* ... modifies members in foo ... */
    }
}

public class Foo { /* ... */ }
  • Должен ли я клонировать объект в вызываемом объекте?
public static void Main()
{
    var foo = new Foo();
    Bar.Baz(foo);
}

public static class Bar
{
    public static void Baz(Foo foo)
    {
        foo = foo.DeepClone();
        /* ... modifies members in foo ... */
    }
}

public class Foo { /* ... */ }

Итак, мои вопросы:

  • Каковы хорошие правила для клонирования объектов в разных языках, особенно в C# и.NET-land?

  • Независимо от ответа, какие есть хорошие способы документировать поведение методов, которые модифицируют аргументы, или методов, которые клонируют объекты?

2 ответа

Решение

Является ли целью метода мутировать объект? Тогда не клонируйте внутри метода. Вы хотите, чтобы побочные эффекты произошли. Обычно имя метода четко указывает на то, что ожидается мутация (например, UpdateCustomer).

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

Методы не должны использовать свои входные данные как пустое пространство. Некоторые в Win32 API делают то, что ужасно сбивает с толку.

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

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

Другие вопросы по тегам