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





По возможности избегайте размышлений. Каждый класс должен нести ответственность за копирование своих собственных свойств и отправку их далее базовому методу.
Я буду. Насколько сложно писать? Определенно легче читать с первого взгляда, чем метод, основанный на отражении.
Да, я бы порекомендовал такой подход.
Его нетрудно читать и, безусловно, легко писать, однако есть проблемы с обслуживанием, которые следует учитывать. Если вы добавляете в класс новое свойство, вам нужно обновить конструктор копирования и тесты, о чем довольно легко забыть.
Я бы не согласился с обновлением конструктора копирования. И в зависимости от того, что изменилось в новом свойстве, я не уверен, что вам нужно будет сделать больше, чем просто повторно запустить существующие тесты. Добавление еще одной пары get / set не требует новых модульных тестов для каждой.
как бы вы скопировали недавно добавленные свойства, если вы не обновите конструктор копирования?
Конструктор копирования в основном означает, что у вас есть единственный параметр, который является объектом, который вы собираетесь скопировать.
Кроме того, делайте глубокую копию, а не мелкую.
Если вы не знаете, что такое глубокие и мелкие копии, то вот в чем дело:
Предположим, вы копируете класс, который имеет одну строку целых чисел в качестве поля.
Неглубокая копия будет:
public class Myclass()
{
private int[] row;
public MyClass(MyClass class)
{
this.row = class.row
}
}
глубокая копия:
public class Myclass()
{
private int[] row;
public MyClass(MyClass class)
{
for(int i = 0; i<class.row.Length;i++)
{
this.row[i] = class.row[i];
}
}
}
Глубокая копия действительно получает актуальные значения и помещает их в новое поле нового объекта, в то время как неглубокая копия копирует только указатели.
С мелкой копией, если вы установите:
row[3] = 5;
А затем распечатайте обе строки, оба отпечатка будут иметь 5 в качестве значения 4-го числа. Однако с глубокой копией это будет только у первого отпечатка, поскольку строки не имеют одинаковых указателей.
Вы можете использовать row.clone(), поскольку C# позволяет клонировать примитивные массивы.
Разве приведенный выше код не завершился ошибкой из-за того, что row никогда не инициализировался?
Вы можете создать неглубокую копию эффективно с отражением, предварительно скомпилировав ее, например, с помощью Expression. Например, вот так.
Для глубоких копий сериализация - самый надежный подход.
Вот конструктор, который я использую. Обратите внимание, что это неглубокий конструктор и довольно упрощенный из-за природы моего базового класса. Должно быть достаточно хорошо, чтобы вы начали.
public partial class LocationView : Location
{
public LocationView() {}
// base class copy constructor
public LocationView(Location value) {
Type t = typeof(Location);
PropertyInfo[] properties = t.GetProperties();
foreach (PropertyInfo pi in properties)
{
pi.SetValue(this, pi.GetValue(value, null), null);
}
}
public Quote Quote { get; set; }
}
Одна строка: foreach (var propertyInfo in typeof(LocationView).BaseType.GetProperties()) propertyInfo.SetValue(this, propertyInfo.GetValue(obj_to_copy_parameter, null), null);, вы также можете использовать инициализатор поля, чтобы читать GetProperties только один раз.
@ChrisMarisic Я стараюсь избегать однострочных слов, когда они приносят в жертву читаемость.
См. Также stackoverflow.com/questions/14218989/… Я придумал общее расширение для общих свойств мелкого клонирования.
Вы можете ссылаться на пакеты valueinjecter и Fastflect nuget и использовать:
public class Myclass()
{
private string _property;
public MyClass(MyClass obj)
{
this.InjectFrom(obj.DeepClone());
}
}
Почему нет голосов? Кто-нибудь может подтвердить, работает ли это?
так что просто для пояснения, было бы лучше, если бы у вас был собственный конструктор копирования для каждого класса, который явно отображает свойства?