仿制药和元帅/ UnMarshal。我在这里错过了什么?

时间:2011-09-23 12:19:32

标签: delphi generics marshalling

更好地提及: 我正在使用Delphi XE2 - 但XE或2010也应该这样做: - )

此问题现在位于Quality Central QC#99313,请将其投票: - )

截至2011年10月20日,Embarcadero已将QC报告标记为已解决。 解决方案由SilverKnight提供。但是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实现Marshal方法。 据我所知 - 我应该为TTestObject和美丽注册一个转换器 它 - 为每个元素调用Marshal。

TTestObject的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);

通用TTestObjectList Marshal方法:

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;

当然我有类似的功能用于恢复(unmarshal)。 但上面的代码应该可行 - 至少据我所知。

所以如果有人能指出我的话:

为什么列表无法编组?

我知道我的名单上有TJsonMarshal属性 - 但它也有转换器/还原器。

更改为TTypeStringConverter(而不是TTypeObjectConverter)将返回有效的字符串。但我喜欢一直在研究TJsonObject的想法。否则,当从字符串解组到TTestObject时,我会遇到同样的问题(或类似的东西)。

欢迎任何建议/想法。

2 个答案:

答案 0 :(得分:4)

这是“修复”Delphi XE2上的问题的“解决方法”(我能够复制相同的运行时错误)。

请注意,在创建Marshal变量时,在项目中定义了以下代码:

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

将两行更改为:

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

解决了问题 - 然后由TOndrej提供的测试应用程序无误地执行。

答案 1 :(得分:2)

我不确定你为什么会收到这个错误。在Delphi XE中,以下似乎对我有用:

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.