इसका बेहतर उल्लेख करें: मैं डेल्फी एक्सई 2 का उपयोग कर रहा हूं - लेकिन एक्सई या 2010 को भी चाल चलनी चाहिए :-)

यह प्रश्न अब क्वालिटी सेंट्रल में है QC#99313 कृपया वोट करें इसे ऊपर :-)

10-20-2011 तक Embarcadero ने QC रिपोर्ट को हल के रूप में चिह्नित किया है। सिल्वरकेनाइट द्वारा समाधान प्रदान किया गया था। लेकिन Embarcadero से जानकारी की कमी मुझे चिंतित करती है। चूंकि समाधान XE(2) हेल्प सिस्टम, अन्य फ़ोरम और CC में बताए गए स्रोत कोड के अलावा अन्य स्रोत कोड का उपयोग करने का सुझाव देता है। लेकिन खुद क्यूसी पर एक नजर डालें।

इस प्रकार की घोषणाओं को देखते हुए:

type
TTestObject : Class
    aList : TStringList;
    function Marshal : TJSonObject;
  end;

  TTestObjectList<T:TestObject> : Class(TObjectList<T>)
    function Marshal : TJSonObject; // How to write this ? 
  end;

मैं TTestObjectList के लिए मार्शल विधि लागू करना चाहता हूं। मेरे सर्वोत्तम ज्ञान के लिए - मुझे TTestObject के लिए एक कनवर्टर पंजीकृत करना चाहिए और इसकी सुंदरता के लिए - प्रत्येक तत्व के लिए मार्शल को कॉल करें।

TTestObject के लिए मार्शल इस कनवर्टर को पंजीकृत करता है:

RegisterConverter(TStringList,
  function(Data: TObject): TListOfStrings
  var
    i, Count: Integer;
  begin
    Count := TStringList(Data).Count;
    SetLength(Result, Count);
    for i := 0 to Count - 1 do
      Result[i] := TStringList(Data)[i];
  end);

जेनेरिक TTestObjectList मार्शल विधि:

function TTestObjectList<T>.Marshal: TJSONObject;
var
Mar : TJsonMarshal;  // is actually a property on the list.
begin
  Mar := TJsonMarshal.Create(TJSONConverter.Create);
  try
    RegisterConverter(TTestObject,
      function(Data: TObject): TObject
      begin
        Result := TTestObject(Data).Marshal;
      end);
    Result := Mar.Marshal(Self) as TJSONObject;
  finally
    Mar.Free;
  end;
end;

सूची का उपयोग करने का एक सरलीकृत उदाहरण यहां दिया गया है।

var
  aTestobj : TTestObject; 
  aList : TTestObjectList<TTestObject>;
  aJsonObject : TJsonObject;
begin
  aTestObj := TTestObject.Create; // constructor creates and fills TStringlist with dummy data.
  aJsonObject := aTestObj.Marshal; // This works as intended.

  aList := TTestObjectList<TTestObject>.Create;
  aJsonObject := aList.Marshal; // Fails with tkpointer is unknown .... 
end;

बेशक मेरे पास पुनर्स्थापित करने के लिए समान कार्यक्षमता है (अनमर्शल)। लेकिन उपरोक्त कोड काम करना चाहिए - कम से कम मेरे सर्वोत्तम ज्ञान के लिए।

तो अगर कोई मुझे इंगित कर सकता है:

सूची मार्शल करने में विफल क्यों है?

मुझे पता है कि मेरे पास मेरी सूची में टीजेसन मार्शल संपत्ति है - लेकिन इसमें कनवर्टर/रिवर्टर भी है।

एक TTypeStringConverter (TTypeObjectConverter के बजाय) में बदलने से एक वैध स्ट्रिंग वापस आ जाएगी। लेकिन मुझे एक TJsonObject पर काम करने का विचार पसंद है। अन्यथा मुझे एक ही समस्या (या कुछ समान) होगी जब एक स्ट्रिंग से TTestObject पर अनमर्शलिंग करते समय।

किसी भी सलाह/विचारों का स्वागत है।

4
Bimmer_R 23 सितंबर 2011, 16:19
मुझे विश्वास नहीं हो रहा है कि एम्बरकेडेरो ने तय किया है --- यह एक वर्कअराउंड है - अगर यह तय किया गया था, तो उनके पास एक ओवरलोडेड कंस्ट्रक्टर नहीं होगा जो आपको अपने उदाहरण में पास करने की अनुमति देता है! या, इस विशेष मामले में, किसी भी निर्माता का उपयोग करते समय वस्तु को कार्य करना चाहिए। मैं कहूंगा कि अभी भी एक बग मौजूद है। मैंने क्यूए में उन्हें "उपयोगकर्ता त्रुटि" के रूप में बंद करने पर पुनर्विचार करने के लिए पोस्ट किया है
 – 
SilverKnight
22 अक्टूबर 2011, 02:08

2 जवाब

सबसे बढ़िया उत्तर

मुझे यकीन नहीं है कि आपको वह त्रुटि क्यों मिलती है। डेल्फी एक्सई में निम्नलिखित मेरे लिए काम करता प्रतीत होता है:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes, Contnrs,
  Generics.Defaults, Generics.Collections,
  DbxJson, DbxJsonReflect;

type
  TTestObject = class(TObject)
    aList : TStringList;
    function Marshal : TJSonObject;
  public
    constructor Create;
    destructor Destroy; override;
  end;

  TTestObjectList<T:TTestObject,constructor> = class(TObjectList<T>)
    function Marshal: TJSonObject;
    constructor Create;
  end;

{ TTestObject }

constructor TTestObject.Create;
begin
  inherited Create;
  aList := TStringList.Create;
  aList.Add('one');
  aList.Add('two');
  aList.Add('three');
end;

destructor TTestObject.Destroy;
begin
  aList.Free;
  inherited;
end;

function TTestObject.Marshal: TJSonObject;
var
  Marshal: TJSONMarshal;
begin
  Marshal := TJSONMarshal.Create(TJSONConverter.Create);
  try
    Marshal.RegisterConverter(TStringList,
      function (Data: TObject): TListOfStrings
      var
        I, Count: Integer;
      begin
        Count := TStringList(Data).Count;
        SetLength(Result, Count);
        for I := 0 to Count - 1 do
          Result[I] := TStringList(Data)[I];
      end
      );
    Result := Marshal.Marshal(Self) as TJSONObject;
  finally
    Marshal.Free;
  end;
end;

{ TTestObjectList<T> }

constructor TTestObjectList<T>.Create;
begin
  inherited Create;
  Add(T.Create);
  Add(T.Create);
end;

function TTestObjectList<T>.Marshal: TJSonObject;
var
  Marshal: TJsonMarshal;
begin
  Marshal := TJSONMarshal.Create(TJSONConverter.Create);
  try
    Marshal.RegisterConverter(TTestObject,
      function (Data: TObject): TObject
      begin
        Result := T(Data).Marshal;
      end
      );
    Result := Marshal.Marshal(Self) as TJSONObject;
  finally
    Marshal.Free;
  end;
end;

procedure Main;
var
  aTestobj : TTestObject;
  aList : TTestObjectList<TTestObject>;
  aJsonObject : TJsonObject;
begin
  aTestObj := TTestObject.Create;
  aJsonObject := aTestObj.Marshal;
  Writeln(aJsonObject.ToString);

  Writeln;
  aList := TTestObjectList<TTestObject>.Create;
  aJsonObject := aList.Marshal;
  Writeln(aJsonObject.ToString);

  Readln;
end;

begin
  try
    Main;
  except
    on E: Exception do
    begin
      ExitCode := 1;
      Writeln(Format('[%s] %s', [E.ClassName, E.Message]));
    end;
  end;
end.
2
Ondrej Kelle 23 सितंबर 2011, 17:21
एक्सई में बस अपना कोड आज़माएं - और मुझे स्वीकार करना होगा। यह काम करता हैं। मुझे इसके साथ कुछ और जटिल चीजों को आजमाना होगा। मुझे कुछ घंटे दो और मैं वापस आ जाऊंगा। मैं थोड़ी बड़ी परियोजना के साथ जांच करना चाहता हूं - यह देखने के लिए कि क्या समस्या होती है।
 – 
Bimmer_R
23 सितंबर 2011, 18:46
नमस्ते फिर से.. देरी के लिए क्षमा करें। मैंने अब XE2 में कोड का परीक्षण किया है ... और यह ठीक उसी तरह विफल रहता है जैसे मेरा कोड करता है ???? शायद XE2 में मार्शलिंग में कोई समस्या है? मैं जेनरिक के लिए नया हूं - और जिस तरह से आप कंस्ट्रक्टर को टाइप डिक्लेरेशन में शामिल करते हैं वह बिल्कुल शानदार है। बस इसके लिए मैं आपको उत्तर के रूप में कोड स्वीकार करने को तैयार हूं - यहां तक ​​​​कि यह केवल एक्सई में काम करता है :-)
 – 
Bimmer_R
24 सितंबर 2011, 00:26
1
समस्या को अब QC#99313 में बढ़ावा दिया गया है। Tondrej से कोड उदाहरण के साथ।
 – 
Bimmer_R
27 सितंबर 2011, 14:15

डेल्फी XE2 पर समस्या को "ठीक" करने के लिए यहां एक "कामकाज" है (मैं उसी रन टाइम त्रुटि को डुप्लिकेट करने में सक्षम था)।

ध्यान दें कि मार्शल वेरिएबल बनाते समय निम्न कोड को प्रोजेक्ट में परिभाषित किया गया है:

Marshal := TJSONMarshal.Create(TJSONConverter.Create);

इसमें दोनों पंक्तियों को बदलना:

Marshal := TJSONMarshal.Create;  //use the default constructor - which does the same thing as TJSONConvert.Create already

समस्या का समाधान करता है - टोंड्रेज द्वारा प्रदान किया गया परीक्षण एप्लिकेशन बिना त्रुटि के निष्पादित होता है।

4
SilverKnight 18 अक्टूबर 2011, 19:48
+1 उसके लिए :-) ... मुझे यह स्वीकार करना होगा कि TJSONMarshal.Create के साथ कंस्ट्रक्टर का उपयोग करना एक आदत है। लेकिन मुझे नहीं पता था कि यह वास्तव में उस जानकारी के लिए .. thx के बिना भी ऐसा ही करता था।
 – 
Bimmer_R
19 अक्टूबर 2011, 22:34