C# Скопировать данные объекта в другой объект
Класс не один и тот же в зависимости от ситуации.
Класс не один и тот же в зависимости от ситуации.
это как, речь идет о наследовании?
Класс не один и тот же в зависимости от ситуации.
В общем случае это бессысленно.
Если это какие-то конкретные свойства, то можно у класса эти поля пометитьсоответствующим атрибутом и копировать согласно атрибутам.
Типа если свойство N в объекте a класса A помечено этим атрибутом, а в объекте b класса B также имеется свойство N такогоже типа и тоже помечено нашим атрибутом - производим копирование.
я только начинаю разбираться в шарпе, так что может чего-то не понимаю....
А нельзя попробовать конструктором копирования?:confused:
Можно и так, в зависимости от того, какую функциональность хочет реализовать автор топика.
Если копировать всё подряд (одноимённые и однотипные свойства) - то можно обойтись без атрибутов, если же он хочет избирательно копировать - нужны атрибуты.
[QUOTE=EuGenius]А нельзя попробовать конструктором копирования?[/QUOTE]
Конструктор копирования можно (строго) определить только в контексте одного класса (в наследниках его всегда можно перекрыть). Автор вопроса хотел максимально широкой функциональности, когда требуется копировать свойства у объектов разных классов.
Оба объекта имеют один тип, но этот класс в зависимости от ситуации может различаться - это может быть некоторый класс N или один из его наследников.
Хотелось бы реализовать копирование в базовом классе, чтобы избавиться от перекрытия этого метода в дочерних классах.
Сначала создаём методы копирования значения:
[SIZE=2][FONT=Courier New]{[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#008080] MethodInfo[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] memberwiseClone = o.GetType().[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]GetMethod([/FONT][/SIZE][FONT=Courier New][SIZE=2][COLOR=#800000]"MemberwiseClone"[/COLOR][/SIZE][SIZE=2], [/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][SIZE=2].Instance | [/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New].NonPublic);[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff] return[/COLOR][/SIZE][SIZE=2] (T)memberwiseClone.Invoke(o, [/SIZE][SIZE=2][COLOR=#0000ff]null[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New]);[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]}[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff]static[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] T CreateDeepCopy<T>(T o)[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]{[/FONT][/SIZE]
[SIZE=2][FONT=Courier New] T copy = CreateShallowCopy(o);[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff] foreach[/COLOR][/SIZE][SIZE=2] ([/SIZE][SIZE=2][COLOR=#008080]FieldInfo[/COLOR][/SIZE][SIZE=2] f [/SIZE][SIZE=2][COLOR=#0000ff]in [/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]typeof[/COLOR][/SIZE][SIZE=2](T).GetFields([/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][SIZE=2].Instance | [/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][SIZE=2].NonPublic | [/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New].Public))[/FONT][/SIZE]
[SIZE=2][FONT=Courier New] {[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff] object[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] original = f.GetValue(o);[/FONT][/SIZE]
[SIZE=2][FONT=Courier New] f.SetValue(copy, CreateDeepCopy(original));[/FONT][/SIZE]
[SIZE=2][FONT=Courier New] }[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff] return[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] copy;[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]}[/FONT][/SIZE]
Теперь, собственно, методы для копирования одного экземпляра в другой:
[SIZE=2][FONT=Courier New]{[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#008080] Type[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] tx = x.GetType();[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#008080] Type[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] ty = y.GetType();[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff] foreach[/COLOR][/SIZE][SIZE=2] ([/SIZE][SIZE=2][COLOR=#008080]FieldInfo[/COLOR][/SIZE][SIZE=2] f [/SIZE][SIZE=2][COLOR=#0000ff]in[/COLOR][/SIZE][SIZE=2] tx.GetFields([/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][SIZE=2].Public | [/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][SIZE=2].NonPublic | [/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New].Instance))[/FONT][/SIZE]
[SIZE=2][FONT=Courier New] {[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff] object[/COLOR][/SIZE][SIZE=2] copy = CreateShallowCopy<[/SIZE][SIZE=2][COLOR=#0000ff]object[/COLOR][/SIZE][SIZE=2]>(f.GetValue(x)); [/SIZE][SIZE=2][COLOR=#008000]//Копируем поле экземпляра x[/COLOR][/SIZE][/FONT]
[SIZE=2][FONT=Courier New] f.SetValue(y, copy); [/FONT][/SIZE][SIZE=2][COLOR=#008000][FONT=Courier New]//Переносим значение в экземпляр y[/FONT][/COLOR][/SIZE]
[SIZE=2][FONT=Courier New] }[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]}[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff]static [/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]void[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] DeepCopyObject<T>(T x, T y)[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]{[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#008080] Type[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] tx = x.GetType();[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#008080] Type[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] ty = y.GetType();[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff] foreach[/COLOR][/SIZE][SIZE=2] ([/SIZE][SIZE=2][COLOR=#008080]FieldInfo[/COLOR][/SIZE][SIZE=2] f [/SIZE][SIZE=2][COLOR=#0000ff]in[/COLOR][/SIZE][SIZE=2] tx.GetFields([/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][SIZE=2].Public | [/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][SIZE=2].NonPublic | [/SIZE][SIZE=2][COLOR=#008080]BindingFlags[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New].Instance))[/FONT][/SIZE]
[SIZE=2][FONT=Courier New] {[/FONT][/SIZE]
[FONT=Courier New][SIZE=2][COLOR=#0000ff] object[/COLOR][/SIZE][SIZE=2] copy = CreateDeepCopy<[/SIZE][SIZE=2][COLOR=#0000ff]object[/COLOR][/SIZE][SIZE=2]>(f.GetValue(x)); [/SIZE][SIZE=2][COLOR=#008000]//Копируем поле экземпляра x[/COLOR][/SIZE][/FONT]
[SIZE=2][FONT=Courier New] f.SetValue(y, copy); [/FONT][/SIZE][SIZE=2][COLOR=#008000][FONT=Courier New]//Переносим значение в экземпляр y[/FONT][/COLOR][/SIZE]
[SIZE=2][FONT=Courier New] }[/FONT][/SIZE]
[SIZE=2][FONT=Courier New]}[/FONT] [/SIZE]
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace Proba
{
class Clone
{
public static T CreateShallowCopy<T>(T o)
{
try
{
MethodInfo memberwiseClone = o.GetType().GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
return (T)memberwiseClone.Invoke(o, null);
}
catch
{
return o;
}
}
public static T CreateDeepCopy<T>(T o)
{
T copy = CreateShallowCopy(o);
foreach (FieldInfo f in typeof(T).GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
object original = f.GetValue(o);
f.SetValue(copy, CreateDeepCopy(original));
}
return copy;
}
}
//---------------------------------------------------------
public class SubSignal
{
public string str;
}
public class Signal
{
public double Value;
public ulong Time;
public string str;
public SubSignal str2 = new SubSignal();
public Signal() { }
public Signal(double v, ulong t)
{
Value = v;
Time = t;
}
}
//---------------------------------------------------------
public class Proba
{
static void Main(string[] args)
{
Signal s = new Signal(1.0, 2);
s.str = "hhhh";
s.str2.str = "hhhh";
Signal ss = Clone.CreateDeepCopy<Signal>(s);
ss.Time = 3;
}
}
}
!!!ВНИМАНИЕ:
Поставте "брейк поинт" на строку "ss.Time = 3;" и посмотрите мышью на содержимое:
ss.str = "\0\0[][]";
ss.str2.str = "hhhh";
.
Странно, должно быть одинаковым.
С уважением.
По-моему какой-то спам.
Ваш ответ не по сути моего вопроса.
Не решенные технически вопросы всегда актуальны, если вы знаете ответ, пожалуйста напишите.
А вы что, задали какой-то вопрос? Чего-то я его не вижу?
Поставте "брейк поинт" на строку "ss.Time = 3;" и посмотрите мышью на содержимое:
ss.str = "\0\0[][]"; ПОЧЕМУ???
ss.str2.str = "hhhh";
Странно, должно быть одинаковым с
s.str = "hhhh";
s.str2.str = "hhhh";
В общем-то выход может быть таким:
public static T CreateDeepCopy<T>(T o)
{
try
{
bool recursion = false;
T copy = CreateShallowCopy(o);
foreach (FieldInfo f in typeof(T).GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
object original = f.GetValue(o);
f.SetValue(copy, CreateDeepCopy(original));
recursion = true;
}
return recursion == true ? copy : o;
}
catch
{
return o;
}
}
Но хотелось бы узнать вариант более элегантный.
Если есть вариант, скажите если нет, пусть тема уйдет в нибытие, откуда и вернулась.
Смотрите ФАК. Массивы и строки в реализации ЗАЗ-а копируются некорректно. Я сделал понастоящему универсальное решение.
Если есть у вас интерес, прокоментируйте (или ссылку) разницу (како-то соотношение производительности) использования рефлекшена и конструктора копирования (например).
Чиво?
Конструкторы копирования остались в C++. Они были нужны исключительно из-за нечеловеческого маршаллинга параметров в нем.
В .NET стандартным решением является использование IClonable интерфейса или переопределение метода Clone для копирования объектов (если того требует задача).
Подобный копировщик я рассматриваю скорее как умозрительное упражнение - уж очень медленным будет он на большом количестве объектов с массивами и прочим.
Как альтернативу копировщику можно рассматривать двоичный сериализатор, у него также есть кое какие ограничения (обязательное наличие публичного конструктора без параметров и атрибута Serializable у типа), но их можно легко удовлетворить, тем более что сериализатор предоставляет большую гибкость при десериализации объекта (помогает например при синглтонах).