Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

C# Скопировать данные объекта в другой объект

17K
13 января 2007 года
Mexes
10 / / 19.08.2006
Можно ли как-нибудь по-простому (не перекрывая метод для каждого наследуемого типа) скопировать данные объекта [FONT="Courier New"]a[/FONT] класса [FONT="Courier New"]X[/FONT] в объект [FONT="Courier New"]b[/FONT] класса [FONT="Courier New"]X[/FONT]?
Класс не один и тот же в зависимости от ситуации.
17K
13 января 2007 года
Mexes
10 / / 19.08.2006
Не создать копию, а скопировать в существующий объект b.
242
13 января 2007 года
Оlga
2.2K / / 04.02.2006
приведи конкретный пример, а то перечитав твой вопрос я до конца не поняла что ты хочешь сделать.
Цитата:

Класс не один и тот же в зависимости от ситуации.


это как, речь идет о наследовании?

5
13 января 2007 года
hardcase
4.5K / / 09.08.2005
Цитата: Mexes
Можно ли как-нибудь по-простому (не перекрывая метод для каждого наследуемого типа) скопировать данные объекта [FONT="Courier New"]a[/FONT] класса [FONT="Courier New"]X[/FONT] в объект [FONT="Courier New"]b[/FONT] класса [FONT="Courier New"]X[/FONT]?
Класс не один и тот же в зависимости от ситуации.


В общем случае это бессысленно.
Если это какие-то конкретные свойства, то можно у класса эти поля пометитьсоответствующим атрибутом и копировать согласно атрибутам.
Типа если свойство N в объекте a класса A помечено этим атрибутом, а в объекте b класса B также имеется свойство N такогоже типа и тоже помечено нашим атрибутом - производим копирование.

355
14 января 2007 года
<SCORP>
786 / / 21.10.2006
а нельзя разве пробежаться по полям обоих объектов, если уж они одного типа, и скопировать значения?
я только начинаю разбираться в шарпе, так что может чего-то не понимаю....
9.0K
14 января 2007 года
EuGenius
48 / / 12.01.2007
Я может не понял вопроса...
А нельзя попробовать конструктором копирования?:confused:
5
14 января 2007 года
hardcase
4.5K / / 09.08.2005
[QUOTE=<SCORP>;166530]а нельзя разве пробежаться по полям обоих объектов, если уж они одного типа, и скопировать значения?[/QUOTE]
Можно и так, в зависимости от того, какую функциональность хочет реализовать автор топика.
Если копировать всё подряд (одноимённые и однотипные свойства) - то можно обойтись без атрибутов, если же он хочет избирательно копировать - нужны атрибуты.

[QUOTE=EuGenius]А нельзя попробовать конструктором копирования?[/QUOTE]
Конструктор копирования можно (строго) определить только в контексте одного класса (в наследниках его всегда можно перекрыть). Автор вопроса хотел максимально широкой функциональности, когда требуется копировать свойства у объектов разных классов.
17K
14 января 2007 года
Mexes
10 / / 19.08.2006
Объекты a и b уже существуют, так что ни о каких конструкторах и MemberwiseClone() речь не идет. Скопировать нужно все поля.

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

Хотелось бы реализовать копирование в базовом классе, чтобы избавиться от перекрытия этого метода в дочерних классах.
273
14 января 2007 года
3A3-968M
1.2K / / 22.12.2005
Тебе нужно поверхностное копирование или глубокое (про разницу читаем здесь: http://forum.codenet.ru/showpost.php?p=154925&postcount=14). Хотя неважно, вот тебе реализация:
Сначала создаём методы копирования значения:
Код:
[SIZE=2][COLOR=#0000ff][FONT=Courier New]static[/FONT][/COLOR][/SIZE][SIZE=2][FONT=Courier New] T CreateShallowCopy<T>(T o)[/FONT][/SIZE]
[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][COLOR=#0000ff][FONT=Courier New]static [/FONT][/COLOR][/SIZE][FONT=Courier New][SIZE=2][COLOR=#0000ff]void[/COLOR][/SIZE][/FONT][SIZE=2][FONT=Courier New] ShallowCopyObject<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 = 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]
41K
28 ноября 2008 года
lleeoo
13 / / 28.11.2008
Запустите, пример рабочий.

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";
.
Странно, должно быть одинаковым.
С уважением.
288
28 ноября 2008 года
nikitozz
1.2K / / 09.03.2007
Вы вообще дату темы видели? Где только умудряются их откапывать.
По-моему какой-то спам.
41K
28 ноября 2008 года
lleeoo
13 / / 28.11.2008
Уважаемый nikitozz-Специалист дату темы прекрасно вижу.
Ваш ответ не по сути моего вопроса.
Не решенные технически вопросы всегда актуальны, если вы знаете ответ, пожалуйста напишите.
14
28 ноября 2008 года
Phodopus
3.3K / / 19.06.2008
Цитата: lleeoo
Ваш ответ не по сути моего вопроса.


А вы что, задали какой-то вопрос? Чего-то я его не вижу?

41K
28 ноября 2008 года
lleeoo
13 / / 28.11.2008
Вопрос заключался в том, что приведенное решение клонирования объектов, является универсальным для всех типов, это здорово, но есть небольшая неточность. В примере я ее указал, повторюсь:

Поставте "брейк поинт" на строку "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;
}
}


Но хотелось бы узнать вариант более элегантный.
Если есть вариант, скажите если нет, пусть тема уйдет в нибытие, откуда и вернулась.
5
29 ноября 2008 года
hardcase
4.5K / / 09.08.2005
Цитата: lleeoo
Вопрос заключался в том, что приведенное решение клонирования объектов, является универсальным для всех типов, это здорово, но есть небольшая неточность. В примере я ее указал, повторюсь:

Смотрите ФАК. Массивы и строки в реализации ЗАЗ-а копируются некорректно. Я сделал понастоящему универсальное решение.

41K
01 декабря 2008 года
lleeoo
13 / / 28.11.2008
Классное решение.

Если есть у вас интерес, прокоментируйте (или ссылку) разницу (како-то соотношение производительности) использования рефлекшена и конструктора копирования (например).
5
01 декабря 2008 года
hardcase
4.5K / / 09.08.2005
Цитата: lleeoo
Если есть у вас интерес, прокоментируйте (или ссылку) разницу (како-то соотношение производительности) использования рефлекшена и конструктора копирования (например).

Чиво?
Конструкторы копирования остались в C++. Они были нужны исключительно из-за нечеловеческого маршаллинга параметров в нем.
В .NET стандартным решением является использование IClonable интерфейса или переопределение метода Clone для копирования объектов (если того требует задача).
Подобный копировщик я рассматриваю скорее как умозрительное упражнение - уж очень медленным будет он на большом количестве объектов с массивами и прочим.
Как альтернативу копировщику можно рассматривать двоичный сериализатор, у него также есть кое какие ограничения (обязательное наличие публичного конструктора без параметров и атрибута Serializable у типа), но их можно легко удовлетворить, тем более что сериализатор предоставляет большую гибкость при десериализации объекта (помогает например при синглтонах).

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог