Przypisanie wartości klasy

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:

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:

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

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:

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.

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

test3.errors_data[0].FromJsonString(test2.ToJsonString); 
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

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:

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?

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

{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: ???

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?

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ń):

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

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?

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.

0

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

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Ć

0

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

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:

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

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

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

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

0

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

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:

uses DBXJSON, DBXJSONReflect, Vcl.StdCtrls;

Dodane zmienne:

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

Delkaracja klas:

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:

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:

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ą :)

0

Zmień to na:

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...

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