Przypisanie wartości klasy

Przypisanie wartości klasy
CZ
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 13
0

Znalazłem w internecie program JSONtoDelphiClass (http://www.pgeorgiev.com/?p=1832). Wszystko fajnie, ale mam problem z wykorzystaniem wygenerowanej klasy w kodzie. I teraz konkrety: wygenerowany kod wygląda tak:

Kopiuj
interface

uses Generics.Collections, Rest.Json;

type

TErrors_dataClass = class
private
  FArtykul: String;
  FCode: String;
public
  property artykul: String read FArtykul write FArtykul;
  property code: String read FCode write FCode;
  function ToJsonString: string;
  class function FromJsonString(AJsonString: string): TErrors_dataClass;
end;

TItemClass = class
private
  FErrors: String;
  FErrors_data: TArray<TErrors_dataClass>;  
public
  property errors: String read FErrors write FErrors;
  property errors_data: TArray<TErrors_dataClass> read FErrors_data write FErrors_data;
  destructor Destroy; override;
  function ToJsonString: string;
  class function FromJsonString(AJsonString: string): TItemClass;
end;

TRootClass = class
private
  FItems: TArray<TItemClass>;
public
  property Items: TArray<TItemClass> read FItems write FItems;
  destructor Destroy; override;
  function ToJsonString: string;
  class function FromJsonString(AJsonString: string): TRootClass;
end; 

Natomiast moja nieśmiała próba użycia tak:

Kopiuj
procedure TForm6.Button3Click(Sender: TObject);
var
test:unit7.TRootClass;
  test2:unit7.TErrors_dataClass;
  test3:unit7.TItemClass;
begin
     test2:=unit7.TErrors_dataClass.Create;
     test2.artykul:='p';
     test2.code:='y';
            showmessage(  test2.ToJsonString);
     test3:=unit7.TItemClass.Create;
     test3.errors:='ooo';
     test3.errors_data[0]:=unit7.TErrors_dataClass.Create;
     test3.errors_data[0].FromJsonString(test2.ToJsonString); 

            showmessage(test3.ToJsonString);

end;
 

Kompilować się kompiluje, ale przy próbie użycia wyświetla mi AV (00000000), jakbym próbował się dostać do nieistniejącego adresu. Nawet nie wiem co robię źle

WL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1084
0

Do czego chcesz to wykorzystać?
Bo to jest odpowiednik XML Binding, tylko tu mamy JSON Binding... Przydaje się to, kiedy masz już dane w JSON i chcesz je wygodnie obrabiać przy pomocy obiktowego kodu.
Natomiast jeśli interesuje Cię zrzut obiektów do JSON i z powrotem (czyli serializacja i deserializacja), to są lepsze biblioteki - np. SvSerializer.

Dwa - gdzie dokładnie jest ten błąd? W której linii występuje AV?
Pewnie tu:

Kopiuj
test3.errors_data[0]:=unit7.TErrors_dataClass.Create;

Zresztą, szkoda czasu na wróżenie z fusów... Nie ma kodu, deklaracja to mało.
Ale wydaje mi się, że ta tablica nie została zainicjowana, a próbujesz przypisach do niej element na indeksie 0.

Gdybyś odczytał to z JSONa, to mógłbyś pobrać dane. Ale nie dodać nowego elementu do tablicy...
A przynajmniej nie w ten sposób.

CZ
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 13
0

Chcę stworzyć JSONa o takiej samej składni jak JSON na podstawie którego wygenerowałem unit z klasami. Ten unit7.pas to unit wygenerowany przez program który podałem. Na podstawie wzorcowego JSONa wypluł mi deklarację klas, i teraz chcę używając tych klas utworzyć JSONa wypełnionego moimi danymi. Linia AV to

Kopiuj
test3.errors_data[0].FromJsonString(test2.ToJsonString); 
WL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1084
1
człowiek_zwany_koniem napisał(a):

Chcę stworzyć JSONa o takiej samej składni jak JSON na podstawie którego wygenerowałem unit z klasami.

IMO to nie zadziała z tym kodem. Możesz edytować dane, ale nie możesz dodawać nowych danych do typów tablicowych, na co jednoznacznie wskazuje deklaracje tej klasy.
JEśli tak jest, to jest to bardzo słabe...
Dałoby się to w miarę łatwo przepisać, zatem do dzieła!

człowiek_zwany_koniem napisał(a):

Ten unit7.pas to unit wygenerowany przez program który podałem. Na podstawie wzorcowego JSONa wypluł mi deklarację klas, i teraz chcę używając tych klas utworzyć JSONa wypełnionego moimi danymi. Linia AV to

Kopiuj
test3.errors_data[0].FromJsonString(test2.ToJsonString); 

No to dostałeś odpowiedź. To nie ma szans działać w ten sposób; więcej - to zachowuje się poprawnie przy takich a nie innych założeniach.

Ale!
Sprawdź dokładnie gdzie występuje błąd, bo może sprawdzasz nas i siebie w błąd, spróbuj czegoś takiego:

Kopiuj
var
  test  : TRootClass;
  test2 : TErrors_dataClass;
  test3 : TItemClass;
begin
  test2         := TErrors_dataClass.Create;
  test2.artykul :='p';
  test2.code    :='y';

  test3 := TItemClass.Create;
  test3.errors := 'ooo';

  SetLength(test3.errors_data, 1);
  test3.errors_data[0] := TErrors_dataClass.Create;
  test3.errors_data[0].FromJsonString(test2.ToJsonString);
end;

Jak się pomyliłem, to trudno - pisałem z łapy.
Natomiast najważniejsze jest to, że zainicjowałem tablicę, a potem przypisałem do niej element. Ty tego nie robisz, a ta biblioteka - sądząc po tym co pokazałeś w deklaracji, na pewno nie robi tego z automatu.

Jeśli błąd dalej występuje na ostatniej linii, to jest błędny JSON lub biblioteka sobie nie radzi z podanym przez Ciebie JSONem. Ale to by było dziwne, gdyby kod tam w ogóle doszedł...

PS. Po co to ShowMessage? Potrafisz używać debuggera?

CZ
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 13
0

No to kiszka, liczyłem że sobie ułatwię zadanie, a tu klops. Dzięki za pomoc
EDIT:
Ale jeśli pominę fragmenty kodu odpowiedzialne za dodawanie test3.errors_data i zostawię to po prostu puste, to za pomocą funkcji

Kopiuj
{TItemClass}

function TItemClass.ToJsonString: string;
begin
  result := TJson.ObjectToJsonString(self);
end;

dostaję ładnego JSONa. Jeśli wykona bliźniaczą funkcję dla test2 również otrzymuję dane w formacie JSON.
Wniosek: ???

WL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1084
0
człowiek_zwany_koniem napisał(a):

Wniosek: ???

Nie zrozumiałeś tego co napisałem...

Serializacja działa. Fajnie. I co z tego, skoro Twój problem polega na zupełnie czymś innym?

CZ
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 13
0

Chyba istota problemu wygląda inaczej, a mianowicie problem tkwi w przypisywaniu elementu tablicowego do właściwości obiektu (lub klasy). Utworzyłem kod (wszystko w jednym unicie, bez udziwnień):

Kopiuj
type tczesc_pakietu=class(tobject)
  cp1:string;
  cp2:string;
end;

type
tpakiet=class(tobject)
  p1:string;
  p2:array of tczesc_pakietu;
end;

...
Poniżej próba przypisania

Kopiuj
procedure TForm6.Button3Click(Sender: TObject);
var
pakiet:tpakiet;
czesc:tczesc_pakietu;
begin
pakiet:=tpakiet.Create;
czesc:=tczesc_pakietu.Create;
pakiet.p1:='asd';
pakiet.p2[0].cp1:='abc'; <<AV
pakiet.p2[0].cp2:='def';
end;

I teraz pytanie: jak to zrobić poprawnie?

WL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1084
0

Nie, istota problemu jest dokładnie taka jaką opisałem.
Zatem przeczytaj ze zrozumieniem, to co napisałem wcześniej, ponieważ dostałeś odpowiedź jaki dlaczego.

abrakadaber
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6610
0

masz bo widzę, że z wiedzą słabo

Kopiuj
procedure TForm6.Button3Click(Sender: TObject);
var
  pakiet:tpakiet;
begin
  pakiet:=tpakiet.Create;
  pakiet.p1:='asd';
  SetLength(pakiet.p2, 1);
  pakiet.p2 := tczesc_pakietu.Create;
  pakiet.p2[0].cp1:='abc';
  pakiet.p2[0].cp2:='def';
end;

Po pierwsze twoja tablica ma rozmiar 0 - ZERO więc nie możesz się odwołać do żadnego elementu dopóki nie zwiększysz rozmiaru tablicy. Po drugie tym elementem jest OBIEKT więc najpierw należy go STWORZYĆ

CZ
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 13
0

Dzięki @wloochacz! Faktycznie problemem jest nie zainicjowanie tablicy. Prawidłowo napisany kod powinien wyglądać tak:

Kopiuj
procedure TForm6.Button4Click(Sender: TObject);
var
pakiet:tpakiet;
czesc:tczesc_pakietu;
begin

pakiet:=tpakiet.Create;
czesc:=tczesc_pakietu.Create;
pakiet.p1:='asas';

czesc.cp1:='cp1';
czesc.cp2:='cp2';

pakiet.p2[0]:=tczesc_pakietu.Create;
pakiet.p2[1]:=tczesc_pakietu.Create;

pakiet.p2[0].cp1:=czesc.cp1;
pakiet.p2[1].cp2:=czesc.cp2;
memo2.Lines.Add(pakiet.p1+pakiet.p2[0].cp1+pakiet.p2[1].cp2);
end;

Przy czym kluczowe są linijki:

Kopiuj
 
pakiet.p2[0]:=tczesc_pakietu.Create;
pakiet.p2[1]:=tczesc_pakietu.Create;

A więc "problem solved":) Dzięki wielkie @wloochacz

abrakadaber
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6610
0

problem nie jest rozwiązany bo nie ustawiasz rozmiaru tablicy a fakt, że ci działa nie oznacza, że jest OK i że się nie wypieprzy

CZ
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 13
0

@abrakadaber Przy ustawieniu rozmiaru tablicy na sztywno (array [1..n] of tczesc_pakietu) działa, to jest wystarczająca proteza. Generalnie klasa którą mi wygenerował powyższy programik generuje mi problem: 1. uses Generics.Collections i 2. FErrors_data: TArray<TErrors_dataClass>; A co za tym idzie zwykłe setlength nie działa (kompilator zwraca "E2197 Constant object cannot be passed as var parameter ") Odznaczyłem temat bo rozwiązuje to mój problem na teraz, chociaż prawdopodobnie będę nad tym siedział jeszcze z tydzień, bo gdybym jednak to ogarnął to będę miał dużo z górki

abrakadaber
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6610
0

tylko, że w kodzie który się pojawia nigdzie nie masz tablicy statycznej a wszędzie dynamiczne - p2:array of tczesc_pakietu;

CZ
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 13
0

Jakby ktoś jeszcze szukał podobnych informacji:
ostatecznie zrezygnowałem z używania unitu wygenerowanego przez jsontodelphiclass. Zamiast tego zadeklarowałem 2 klasy:
Dodane do uses:

Kopiuj
uses DBXJSON, DBXJSONReflect, Vcl.StdCtrls;

Dodane zmienne:

Kopiuj
 
var
    item: Titemclass;
  kid: Terrors_dataclass;
  JSONString: String;

Delkaracja klas:

Kopiuj
type
 TErrors_dataClass = class
private
  FCode: String;
  FDescription: String;
end;

TItemClass = class
  FErrors: String;
  FErrors_data: array of TErrors_dataclass; 
  procedure AddChild(kid: Terrors_dataclass);
end;

Jak widać mamy tu tablice dynamiczne, a to właśnie było jedno z głównych założeń
KLUCZOWA procedura addchild:

Kopiuj
procedure Titemclass.AddChild(kid: Terrors_dataclass);
begin
  SetLength(Ferrors_data, Length(ferrors_data) + 1);
  Ferrors_data[Length(Ferrors_data) - 1] := kid;
end;

i dalej użycie:

Kopiuj
procedure test;
  begin
    begin
  m := TJSONMarshal.Create(TJSONConverter.Create);
  unm := TJSONUnMarshal.Create;

  m.RegisterConverter(Titemclass, 'Ferrors_data', function(Data: TObject; Field: String): TListOfObjects
  var
    obj: terrors_dataclass;
    I: Integer;

  begin
    SetLength(Result, Length(titemclass(Data).FErrors_data));
    I := Low(Result);
    for obj in titemclass(Data).FErrors_data do
    begin
      Result[I] := obj;
      Inc(I);
    end;
  end);

  unm.RegisterReverter(Titemclass, 'Ferrors_dataclass', procedure(Data: TObject; Field: String; Args: TListOfObjects)
  var
    obj: TObject;
    I: Integer;

  begin
    SetLength(Titemclass(Data).FErrors_data, Length(Args));
    I := Low(Titemclass(Data).FErrors_data);
    for obj in Args do
    begin
      Titemclass(Data).Ferrors_data[I] := Terrors_dataclass(obj);
      Inc(I);
    end
  end);

   item:=titemclass.Create;
   item.FErrors:='lista bledow';
   kid:=terrors_dataclass.Create;
   kid.FCode:='111';
   kid.FDescription:='opis';

   item.AddChild(kid);

  JSONString := m.Marshal(item).ToString;    //wynik <<<<<<<<<<
   result:=m.Marshal(item);
end;

Całe zagadnienie uświadomiło mi jak marnym jestem programistą :)

WL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1084
0

Zmień to na:

Kopiuj
TItemClass = class
strict private  
  TList<TErrors_dataClass>;
  function GetErrors : TList<TErrors_dataClass>;
public
  property Errors : TList<TErrors_dataClass> read GetErrors;
end;

I możesz dodawać usuwać bez fiku-miku.
Serializacja i DeSerializacja, robi się z automatu przy pomocy SvSerializera https://bitbucket.org/soundvibe/delphi-oop
Żadne ułomne JSONReflect i rejestrowanie do niego innych typów nie jest potrzebne.
Poza tym, on to robi naprawdę bardzo dobrze.
Ale jak tam sobie chcesz...

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.