Главная страница
    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.072 c
15-1337747844
Медвежонок Пятачок
2012-05-23 08:37
2013.03.22
Многое здесь было, а этого еще не припомню


6-1256849792
Демо
2009-10-29 23:56
2013.03.22
WSARecv или ReadFile?


1-1300638375
maxstels
2011-03-20 19:26
2013.03.22
Автоматические заполнение заготовок процедур


15-1352991636
AV
2012-11-15 19:00
2013.03.22
Четверговская задача :)


15-1353572399
Иван Уткин
2012-11-22 12:19
2013.03.22
Вопрос по теории вероятностей?





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский