Collection kopyalama

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Cevapla
Kullanıcı avatarı
comfort
Üye
Mesajlar: 214
Kayıt: 28 Ara 2004 06:37
Konum: İzmir
İletişim:

Collection kopyalama

Mesaj gönderen comfort »

Merhaba;

Kod: Tümünü seç

 TInput = class(TCollectionItem)
  private
    Field1:integer
    Field2:string;    
  end;

  TInputs = class(TCollection)
  private
    function GetItem(Index: Integer): TInput;
  public
    function Add: TInput;
    property Item[Index: Integer]: TInput read GetItem;
  end;

var
Inputs:TInputs
implementation
.
.
.
.


inputs değişkenini runtime sırasında oluşturuyorum ve bütün itemları oluşturuyorum. Daha sonra inputs un içinden belli özellikteki item ları (Örneğin field1=1 olanlar) bir fonksiyonla çekmek istiyorum

Kod: Tümünü seç

function FindInput (XParameter:integer): TInputs;
var
  Xinput:TInput;
  I:integer
begin
Result:=  TInputs.Create(TInput);
  for I := 0 to Inputs.Count - 1 do
    if (Inputs.Item[I].field1 = XParameter) then
    begin
      XInput:=Result.add;
      XInput.field1:=Inputs.Item[I].field1;
      XInput.field2:=Inputs.Item[I].field2;
    end;
end;
Aslında yukarıdaki gibi bir kod işimi çözüyor fakat benim gerçek Input sınıfım bu kadar basit olmadığı için bu kod pek uygun gözükmüyor. Bunu yapmanın daha kısa bir yolu var mıdır?
Kullanıcı avatarı
comfort
Üye
Mesajlar: 214
Kayıt: 28 Ara 2004 06:37
Konum: İzmir
İletişim:

Re: Collection kopyalama

Mesaj gönderen comfort »

Ne istediğimi tam anlatabilmek için örnek bir proje hazırladım. Bu projede edit1 in içine yazılan bir sayı kaynak collection da var ise bunu yeni collection içine atmaya çalışıyor ama sonuç boş geliyor.
Dosya ekleri
collection.rar
(7.5 KiB) 89 kere indirildi
Kullanıcı avatarı
sabanakman
Kıdemli Üye
Mesajlar: 3081
Kayıt: 17 Nis 2006 08:11
Konum: Ah bi Antalya olaydı keşke (Ankara)

Re: Collection kopyalama

Mesaj gönderen sabanakman »

"TInput = class(TCollectionItem)" koleksiyon eleman sınıfı için bir adet Assign metodu ezerseniz (override ile yeniden kodlarsanız) bu istediğiniz çok kolay bir biçimde gerçekleşecektir.

Kod: Tümünü seç

type
  TInput = class(TCollectionItem)
  public
    procedure Assign(Source:TPersistent); override;
  private
    Field1: integer;
    Field2: string;
    Field3:string;
  end;

procedure TInput.Assign(Source: TPersistent);
var Src:TInput;
begin
  if Source is TInput then begin
    Src:=TInput(Source);
    Field1:=Src.Field1;
    Field2:=Src.Field2;
    Field3:=Src.Field3;
  end else //inherited Assign(Source);
end;
Artık koleksiyon (Collection) sınıfı Assign ile tüm elemanlarıyla aynen kopyalanabilir durumda olacaktır.

Kod: Tümünü seç

function TForm1.FindInputs(fID: integer): TInputs;
begin
  Result := TInputs.Create(TInput);
  Result.Assign(Inputs);
end;
Kolay gelsin.
Şaban Şahin AKMAN
_________________
Derin olan kuyu değil kısa olan iptir. - .
Kullanıcı avatarı
comfort
Üye
Mesajlar: 214
Kayıt: 28 Ara 2004 06:37
Konum: İzmir
İletişim:

Re: Collection kopyalama

Mesaj gönderen comfort »

evet ama önceden dediğim gibi benim class yapım örnekteki kadar kolay değil. Bir çok field var ve devamlı değişiklik yapıyorum. Bundan daha kolay bir yol olmalı yoksa kodda baya bir değişikliğe gitmem gerekecek.
Kullanıcı avatarı
sabanakman
Kıdemli Üye
Mesajlar: 3081
Kayıt: 17 Nis 2006 08:11
Konum: Ah bi Antalya olaydı keşke (Ankara)

Re: Collection kopyalama

Mesaj gönderen sabanakman »

uses TypInfo eklenerek özellik değerleri dinamik olarak hesaplanıp kopya edilebilir. Bu şekilde kullanabilmek için değerlerin hepsi published property olarak tanımlı olmalı (public, private, protected kısımlarında olmaz).

Kod: Tümünü seç

uses TypInfo;
type
  TInput = class(TCollectionItem)
  public
    procedure Assign(Source:TPersistent); override;
  private
    FField1: integer;
    FField2: string;
    FField3:string;
  published
    property Field1: integer read FField1 write FField1;
    property Field2: string read FField2 write FField2;
    property Field3: string read FField3 write FField3;
  end;

function OzellikKopyala(const Kaynak,Hedef:TObject):Boolean;
var
  Count, Size, I: Integer;
  List: PPropList;
  PropInfo: PPropInfo;
  PropOrEvent, PropValue: string;
begin
  Result:=False;
  Count := GetPropList(Kaynak.ClassInfo, tkAny, nil);
  Size  := Count * SizeOf(Pointer);
  GetMem(List, Size);
  try
    Count := GetPropList(Kaynak.ClassInfo, tkAny, List);
    for I := 0 to Count - 1 do begin
      PropInfo := List^[I];
      if not (PropInfo^.PropType^.Kind  in tkMethods) then begin
        PropValue := VarToStr(GetPropValue(Kaynak, PropInfo^.Name));
        SetPropValue(Hedef, PropInfo^.Name, PropValue);
      end;
    end;
    Result:=True;
  finally
    FreeMem(List);
  end;
end;

procedure TInput.Assign(Source: TPersistent);
begin
  if Source is TInput then begin
    OzellikKopyala(Source,Self);
  end else //inherited Assign(Source);
end;
Burada TInput eleman sınıfına published kısmında ekleyeceğiniz (property) özellikler için herhangi bir değer atama kodu düzenlemeden isteğiniz gerçekleşecektir. Dikkat edilmesi gereken başka bir nokta dizi tipinde property olmamalı. Eğer dizi tipinde özelliği de kullanacaksanız bunu ayrıca Assign metodu içinde kodlamanız gerekmektedir.
Şaban Şahin AKMAN
_________________
Derin olan kuyu değil kısa olan iptir. - .
Kullanıcı avatarı
comfort
Üye
Mesajlar: 214
Kayıt: 28 Ara 2004 06:37
Konum: İzmir
İletişim:

Re: Collection kopyalama

Mesaj gönderen comfort »

Açıkçası bir daha collection kullanırken 2 defa düşüneceğim. List ten ne avantajı var anlamadım. Kullanımıda daha zor.
Kullanıcı avatarı
sabanakman
Kıdemli Üye
Mesajlar: 3081
Kayıt: 17 Nis 2006 08:11
Konum: Ah bi Antalya olaydı keşke (Ankara)

Re: Collection kopyalama

Mesaj gönderen sabanakman »

Eğer liste elemanlarınız sınıf ise tespitinizin sorunuzla pek bir alakası yok aslında. TList ile listenin başka bir kopyasını oluşturmak için bundan daha az kodlama yapamazsınız. Fakat liste elemanlarınız (string benzeri tipli elemanlar için ShortString gibi uzunluğu belli olan tipler kullanılarak) record gibi bir yapı ise, bellek adres ve boyutları bilinen tipler arasında atamayı (System.Move ile) daha az kodlamayla yapabilirsiniz. Bu noktada ise gösterici (Pointer) konusuna hakim olmak gerekmektedir.
Şaban Şahin AKMAN
_________________
Derin olan kuyu değil kısa olan iptir. - .
Cevapla