Pętla "for .. in" na TObjectList - jak to zapisać?

0

Powiedzcie mi proszę, czy pętlę:

for i := 0 to TObjectList.Count -1 do
  Object := TObjectList.Items[i];

mogę zastąpić pętlą for-in, coś w stylu

 for Object in TObjectList.???? do ... 

?

przykład definicji klasy tutaj: http://pastebin.com/Ld8N50zj

3

Nie wiem o co ci chodzi dlaczego TObjectList bo to raczej typ a nie utworzona lista obiektów ale weźmy np.:

type
 TMyObj= class(TObject) //taki prosty obiekt
  private
    fNo: Integer;
  public
     property No: Integer read fNo write fNo;
  end;   
//....
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
  ObjectList: TObjectList<TMyObj>;
  MyObj: TMyObj;
begin
  ObjectList:= TObjectList<TMyObj>.Create;
  ObjectList.OwnsObjects:= True;

  for i:= 0 to 2 do  //dodac z 3 elementy do listy
  begin
    MyObj:= TMyObj.Create;
    MyObj.No:= i;
    ObjectList.Add(MyObj);
  end;

  for i := 0 to ObjectList.Count -1 do
  begin
    MyObj:= ObjectList.Items[i];
    ShowMessage(IntToStr(MyObj.No));
  end;

  for MyObj in ObjectList do
    ShowMessage(IntToStr(MyObj.No));

  ObjectList.Free;
end;

To te 2 ostatnie czyli odczytujące robią to samo.

0
kAzek napisał(a):

Nie wiem o co ci chodzi dlaczego TObjectList bo to raczej typ a nie utworzona lista obiektów

czy to oznacza, że definiując swoją klasę dziedziczącą po TObject bądź nie, a następnie ileś jej obiektów to nie muszę definiować również ObjectList do przechowywania tychże obiektów? Jest jakiś inny, prostszy sposób poza oczywiście zmiennymi?

zrobiłem w ten sposób:

var
  tempOsoba:TOsoba;
begin
  for tempOsoba in fmMain.listaOsob do { fmMain to formularz główny, a listaOsob obiekt klasy dziedziczącej po TObjectList }
      begin
        showMessage(tempOsoba.Nazwisko);
      end;

i kompilator zwraca: [dcc32 Error] raport.pas(120): E2010 Incompatible types: 'TOsoba' and 'Pointer'

3

Chyba problem polega na tym że twoja lista obiektów powinna być typu TObjectList<tosoba> tak jak w przykładzie który podałem wyżej (nie musisz się bawić w jakieś TOsobaList po prostu to znacznie ułatwia życie choć jak chcesz to TOsobaList<tosoba> też chyba może być ważne aby kompilator "wiedział" że ma do czynienia z listą obiektów typu TOsoba). Tylko nie wiem jaką masz wersję Delphi bo aby można było coś takiego zrobić muszą być obsługiwane typy generyczne które zostały wprowadzone dopiero w wersji 2009. Oczywiście uses trzeba dodać Generics.Collections

0

Mam XE3, więc problemu być nie powinno, typy generyczne obsługuje :)
Przyznam, że nie rozumiem zapisu "TOsobaList<tosoba>". Chodzi o dziedziczenie TOsobaList po TOsoba? To nie problem, ale jak wtedy przechowywać obiekty w TOsobaList skoro nie będę dziedziczył po TObjectList? Mam sam dodać metody Add, Delete, wlasności Items?
Poza tym czy jeśli definicja TOsobaList wygląda tak:

type
 type TOsobaList = class(TObjectList)
  private
    function GetItem(AIndex: integer): TOsoba;
    procedure SetItem(AIndex: integer; const Value: TOsoba);
  public
    constructor Create(AWlascicielObiektow: Boolean);
    destructor Destroy; override;
    property Items[AIndex: integer]: TOsoba read GetItem write SetItem; default;
    function Add(AOsoba: TOsoba): integer;
    function FindItem(NazwiskoImie: string): integer;
  end;

to czy kompilator nie wie, że itemy tutaj są typu TOsoba? Widać to szczególnie po parametrze funkcji Add, oraz typie własności Item. Trochę już zgaduję, ale na logikę...

3

Przyznam, że nie rozumiem zapisu "TOsobaList<tosoba>".

No to chyba czas najwyższy nieco na temat typów generycznych poczytać, zanim zacznie się je wykorzystywać;

Zapis ten oznacza, że obiekt klasy TOsobaList<TOsoba> będzie listą obiektów klasy TOsoba, tak samo jak stara wersja TObjectList jest listą obiektów klasy TObject; Generyki dają możliwość stworzenia listy obiektów dowolnej klasy, bez konieczności rzutowania na dany typ czy korzystania z operatorów Is/As.

0

Wstyd, że ja pierdziele :D Z XE3 korzystam od stosunkowo niedawno, w d7 generyków nie było. Dzięki za wyjaśnienia.

EDIT:
@Furious Programming: mam jeszcze jedno pytanie, a google odpowiedzi nie znają. Chcąc stosować typy generyczne muszę dodać do uses bibliotekę System.Generics - nawet środowisko podpowiada takową podczas pisania. Ale dlaczego podczas kompilacji wywala błąd Not Found System.Generics.dcu? Generics.dcu analogicznie.

EIDT:

poszło z Generics.Collections, sorry za niepotrzebne wołanie :)

0

@Furious Programming: sorry, że odświeżam wątek, ale mam jeszcze jedno pytanie odnośnie typów generycznych, na które odpowiedzi nie ma na googlach. W przypadku definiowania własnej listy obiektów dziedziczącej po TListObject mogłem napisać funkcję wyszukującą dany TObject. Przykład poniżej:

function TOsobaList.FindItem(ANazwisko:string):integer;
var
  i:integer:
begin
  result := -1;
  for i :=  0 to self.count -1 do
    if SameText(self.items[i].Nazwisko, ANazwisko) then
    begin
      result := self.items[i].ID;
      break;
    end;
end;

i wtedy był porządek w kodzie. Stosując generyki też mogę użyć podobnego rozwiązania? Z tego co widzę za każdym razem podczas próby zwrócenia np ID człowieka po jego nazwisku muszę robić w kodzie całą pętlę:

...
listaOsob:TOsobaList<TOsoba>
...
for tempOsoba in listaOsob do
  if tempOsoba.Nazwisko = ANazwisko ...
...

czy mam rację? Jeśli chciałbym zrobić to w sposób "koszerny" znów musiałbym zdefiniować własny typ dziedziczący po generyku z metodą FindItem? A to mija się z celem jak na moją logiką skoro są listy obiektów TObjectList :D Wytłumacz mi bardzo proszę.

0

@tomix - a nie możesz po prostu skorzystać z metody FindItem:

{...}
listaOsob: TOsobaList<TOsoba>;
{...}

intIndex := listaOsob.FindItem('Kowalski');

bez korzystania z pętli?

Swoją drogą w metodzie FindItem też możesz wykorzystać pętlę for in:

function TOsobaList.FindItem(ANazwisko: String): Integer;
var
  Osoba: TOsoba;
begin
  Result := -1;

  for Osoba in Items do
    if SameText(Osoba.Nazwisko, ANazwisko) then
    begin
      Result := Osoba.ID;
      Exit;
    end;
end;

lub krótszą wersję, jeśli Twoje Delphi posiada rozbudowaną wersję instrukcji Exit pozwalającej przyjmować parametry (jak w Lazarusie):

function TOsobaList.FindItem(ANazwisko: String): Integer;
var
  Osoba: TOsoba;
begin
  Result := -1;

  for Osoba in Items do
    if SameText(Osoba.Nazwisko, ANazwisko) then
      Exit(Osoba.ID);
end;

To tylko w ramach ciekawostki, jeśli pole Items (lub właściwość, bo pole powinno być FItems) jest listą obiektów klasy TOsoba.

0

@Furious Programming: wprowadziłem Cię zapisem w błąd, miało to wyglądać tak:

var
listaOsob : TObjectList<TOsoba>;
begin
listaOsob := TObjectList<TOsoba>.Create(True);
end;

i teraz żebyś mnie dobrze zrozumiał - klasa TObjectList nie ma metody FindItem, a żeby ją napisać muszę zdefiniować nową klasę dziedziczącą po TObjectList - tak? Myślałem, że generyki oferują w sobie aż tyle, że nie będę ich musiał dziedziczyć i dostosowywać pod siebie (w sensie tworzyć list obiektów jak do tej pory). Jeśli się nie mylę, to typy generyczne muszę stosować tak samo jak w przypadku poniższym aby spełniały moje wymagania co z kolei mija się z celem przerabiania poniższego rozwiązania na generyczne:

 type TOsobaList = class(TObjectList)
  private
    function GetItem(AIndex: integer): TOsoba;
    procedure SetItem(AIndex: integer; const Value: TOsoba);
  public
    constructor Create(AWlascicielObiektow: Boolean);
    destructor Destroy; override;
    property Items[AIndex: integer]: TOsoba read GetItem write SetItem; default;
    function Add(AOsoba: TOsoba): integer;
    function FindItem(NazwiskoImie: string): integer;
  end;

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0