Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];

Вниз

Клонирование объектов   Найти похожие ветки 

 
Омлет ©   (2012-07-10 13:26) [0]

Почему этого нет в Delphi?
Надоело вылавливать баги из-за недоделанных Assign-методов :(


 
icelex ©   (2012-07-10 13:32) [1]

отож и рефлексии :(


 
Компромисс ©   (2012-07-10 13:35) [2]


> Почему этого нет в Delphi?


Из-за отсутствия автоматического управления памятью, наверное.
Разве нельзя написать свой метод clone() или deepClone()?


 
Омлет ©   (2012-07-10 13:43) [3]


> Разве нельзя написать свой метод clone() или deepClone()?

Через RTTI?


 
Компромисс ©   (2012-07-10 13:54) [4]

Омлет ©   (10.07.12 13:43) [3]

Почему обязательно одну реализацию для всех классов и через RTTI? Можно написать вручную
Result := TMyClass.Create();
Result.MyField1 := Self.MyField1;
Result.MyField2 := Self.MyField2;


 
Омлет ©   (2012-07-10 13:57) [5]

> Компромисс ©   (10.07.12 13:54) [4]

Хочется универсальное клонирование для произвольного объекта. Доступа к исходникам (т.е. к приватным полям) может и не быть.
[1] > Надоело вылавливать баги из-за недоделанных Assign-методов :(


 
DevilDevil ©   (2012-07-10 14:03) [6]

{$ifdef fpc}
Function fpc_Copy_internal (Src, Dest, TypeInfo : Pointer) : SizeInt;[external name "FPC_COPY"];
procedure CopyRecord(const dest, source, typeinfo: ptypeinfo);
asm
 {внимание! очень плохо работает в FPC !!!}
 xchg eax, edx
 jmp fpc_Copy_internal
end;
{$else}
procedure CopyRecord(dest, source, typeinfo: pointer);
asm
 jmp System.@CopyRecord
end;
{$endif}

procedure CopyObject(const Dest, Src: TObject);
var
 InitTable: pointer;
 BaseSize, DestSize: integer;
 BaseClass, DestClass, SrcClass: TClass;
begin
 if (Dest = nil) or (Src = nil) then exit; {по идее эксепшн}

 DestClass := TClass(pointer(Dest)^);
 SrcClass := TClass(pointer(Src)^);

 if (DestClass = SrcClass) then BaseClass := DestClass
 else
 if (DestClass.InheritsFrom(SrcClass)) then BaseClass := SrcClass
 else
 if (SrcClass.InheritsFrom(DestClass)) then BaseClass := DestClass
 else
 begin
   BaseClass := DestClass;

   while (BaseClass <> nil) and (not SrcClass.InheritsFrom(BaseClass)) do
   begin
     BaseClass := BaseClass.ClassParent;
   end;

   if (BaseClass = nil) then exit; {но такого не должно быть}
 end;

 // копирование
 DestSize := BaseClass.InstanceSize;  
 while (BaseClass <> TObject) do
 begin
   InitTable := PPointer(Integer(BaseClass) + vmtInitTable)^;
   if (InitTable <> nil) then
   begin
     CopyRecord(pointer(Dest), pointer(Src), InitTable);
     break;
   end;
   BaseClass := BaseClass.ClassParent;
 end;

 BaseSize := BaseClass.InstanceSize;
 if (BaseSize <> DestSize) then Move(pointer(integer(Src)+BaseSize)^, pointer(integer(Dest)+BaseSize)^, DestSize-BaseSize);
end;


 
DevilDevil ©   (2012-07-10 14:13) [7]

Соответственно CloneObject будет типа такого

function CloneObject(const Src: TObject): TObject;
var
InitTable: pointer;
BaseSize, DestSize: integer;
BaseClass: TClass;
Dest: pointer;
begin
 if (Src = nil) then
 begin
    Result := nil;
    exit;
 end;

 BaseClass := TClass(pointer(Src)^);
 DestSize := BaseClass.NewInstance();
 GetMem(Dest, DestSize);
 ZeroMemory(Dest, DestSize);
 TClass(Dest^) := BaseClass;
 Result := TObject(Dest);

// копирование
DestSize := BaseClass.InstanceSize;  
while (BaseClass <> TObject) do
begin
  InitTable := PPointer(Integer(BaseClass) + vmtInitTable)^;
  if (InitTable <> nil) then
  begin
    CopyRecord(pointer(Dest), pointer(Src), InitTable);
    break;
  end;
  BaseClass := BaseClass.ClassParent;
end;

BaseSize := BaseClass.InstanceSize;
if (BaseSize <> DestSize) then Move(pointer(integer(Src)+BaseSize)^, pointer(integer(Dest)+BaseSize)^, DestSize-BaseSize);
end;


 
DevilDevil ©   (2012-07-10 14:14) [8]

сори, очепятка

function CloneObject(const Src: TObject): TObject;
var
InitTable: pointer;
BaseSize, DestSize: integer;
BaseClass: TClass;
Dest: pointer;
begin
if (Src = nil) then
begin
   Result := nil;
   exit;
end;

BaseClass := TClass(pointer(Src)^);
DestSize := BaseClass.InstanceSize;  
GetMem(Dest, DestSize);
ZeroMemory(Dest, DestSize);
TClass(Dest^) := BaseClass;
Result := TObject(Dest);

// копирование
while (BaseClass <> TObject) do
begin
 InitTable := PPointer(Integer(BaseClass) + vmtInitTable)^;
 if (InitTable <> nil) then
 begin
   CopyRecord(pointer(Dest), pointer(Src), InitTable);
   break;
 end;
 BaseClass := BaseClass.ClassParent;
end;

BaseSize := BaseClass.InstanceSize;
if (BaseSize <> DestSize) then Move(pointer(integer(Src)+BaseSize)^, pointer(integer(Dest)+BaseSize)^, DestSize-BaseSize);
end;


 
Омлет ©   (2012-07-10 14:16) [9]

> DevilDevil ©

Интересно, спасибо!
Вроде работает, потестирую на досуге.


 
Sapersky   (2012-07-10 14:23) [10]

Ну если устраивает, что вложенные объекты и не-managed указатели скопируются как ссылки... (Assign вроде как подразумевает создание копий?)


 
Омлет ©   (2012-07-10 14:25) [11]

> Sapersky   (10.07.12 14:23) [10]

А вот об этом не подумал :(


 
DevilDevil ©   (2012-07-10 14:27) [12]

> Омлет ©   (10.07.12 14:16) [9]

ага. скажи потом чё как.
потестируй на разных объектах (как сложных так и простых)
мож чё-то не скопируется


 
DevilDevil ©   (2012-07-10 14:28) [13]

> Ну если устраивает, что вложенные объекты и не-managed указатели
> скопируются как ссылки... (Assign вроде как подразумевает
> создание копий?)


Все сложные типы (строки, варианты, динамические массивы, интерфейсы) - таким образом скопируются по правильному


 
Омлет ©   (2012-07-10 14:30) [14]

> DevilDevil ©   (10.07.12 14:28) [13]
> Все сложные типы (строки, варианты, динамические массивы, интерфейсы) - таким образом скопируются по правильному

Но остается проблема с вложенными объектами..


 
DevilDevil ©   (2012-07-10 14:32) [15]

ну значит допиливай функционал дополнительной "копией" вложенных объектов
иначе никак

* у меня в классе многие экземпляры класса - ссылки. Другим способом особо как-то копировать не приходилось


 
Компромисс ©   (2012-07-10 14:34) [16]

Омлет ©   (10.07.12 13:57) [5]

Если нет доступа к приватным полям, возможно, класс не поддерживает клонирование. В java CloneNotSupportedException как раз для таких случаев. То есть можно извратиться и скопировать/клонировать все поля, но в итоге объект может оказаться некорректным. Например, если у него ссылка на синглтон в каком-то поле.



Страницы: 1 вся ветка

Форум: "Прочее";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.49 MB
Время: 0.066 c
15-1347556136
Dimka Maslov
2012-09-13 21:08
2013.03.22
Обработка исключений


15-1349860163
Sinister
2012-10-10 13:09
2013.03.22
MacBook Pro


3-1277464409
12
2010-06-25 15:13
2013.03.22
Запрос на получение всех конечных узлов дерева


2-1340780940
aka
2012-06-27 11:09
2013.03.22
Удаления пробелов в строке.


15-1338928202
Юрий
2012-06-06 00:30
2013.03.22
С днем рождения ! 6 июня 2012 среда





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский