Delphi 泛型和封送/解封送。我错过了什么?

Delphi 泛型和封送/解封送。我错过了什么?,delphi,generics,marshalling,Delphi,Generics,Marshalling,最好提一下: 我使用的是Delphi XE2-但是XE或2010也应该这样做:-) 这个问题现在在质量中心,请投票表决:-) 截至2011年10月20日,Embarcadero已将质量控制报告标记为已解决。 解决方案由SilverKnight提供。但是缺少来自Embarcadero的信息让我担心。由于该解决方案建议使用XE(2)帮助系统、其他论坛和CC中解释的源代码以外的其他源代码。但您自己也可以看看QC。 给定这些类型声明: type TTestObject : Class aList

最好提一下: 我使用的是Delphi XE2-但是XE或2010也应该这样做:-)

这个问题现在在质量中心,请投票表决:-)

截至2011年10月20日,Embarcadero已将质量控制报告标记为已解决。 解决方案由SilverKnight提供。但是缺少来自Embarcadero的信息让我担心。由于该解决方案建议使用XE(2)帮助系统、其他论坛和CC中解释的源代码以外的其他源代码。但您自己也可以看看QC。

给定这些类型声明:

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

  TTestObjectList<T:TestObject> : Class(TObjectList<T>)
    function Marshal : TJSonObject; // How to write this ? 
  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;
函数TTestObjectList.Marshal:TJSONObject;
变量
Mar:TJsonMarshal;//实际上是列表上的一个属性。
开始
Mar:=TJsonMarshal.Create(TJSONConverter.Create);
尝试
寄存器转换器(TTestObject,
函数(数据:TObject):TObject
开始
结果:=TTestObject(数据)。封送处理;
(完),;
结果:=作为TJSONObject的Mar.Marshall(Self);
最后
三月自由;
结束;
结束;
下面是一个使用列表的简化示例

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;
var
aTestobj:TTestObject;
列表:对象列表;
aJsonObject:TJsonObject;
开始
aTestObj:=TTestObject.Create;//构造函数创建并用伪数据填充TStringlist。
aJsonObject:=aTestObj.Marshal;//这正是我们想要的。
列表:=TTestObjectList.Create;
aJsonObject:=aList.Marshal;//tkpointer失败未知。。。。
结束;
当然,我也有类似的恢复(解组)功能。 但至少就我所知,上面的代码应该可以工作

因此,如果有人能向我指出:

为什么列表无法封送

我知道我的列表中有TJsonMarshal属性,但它也有一个转换器/还原器

更改为TTypeStringConverter(而不是TTypeObjectConverter)将返回有效字符串。但我喜欢一直在TJsonObject上工作的想法。否则,在执行从字符串到TTestoObject的解组时,我也会遇到同样的问题(或类似的问题)


任何建议/想法都是非常受欢迎的。

我不知道你为什么会犯这样的错误。在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.
程序项目1;
{$APPTYPE控制台}
使用
系统、类、Contnrs、,
泛型。默认值,泛型。集合,
DbxJson,DbxJsonReflect;
类型
TTestObject=类(ToObject)
作者:TStringList;
函数封送:TJSonObject;
公众的
构造函数创建;
毁灭者毁灭;推翻
结束;
TTestObjectList=类(ToObjectList)
函数封送:TJSonObject;
构造函数创建;
结束;
{TTestObject}
构造函数tobject.Create;
开始
继承创造;
aList:=TStringList.Create;
列表。添加(‘一’);
添加('two');
添加(‘三’);
结束;
析构函数TTestObject.Destroy;
开始
免费的;
继承;
结束;
函数TTestObject.Marshal:TJSonObject;
变量
元帅:TJSONMarshal;
开始
封送处理:=TJSONMarshal.Create(TJSONConverter.Create);
尝试
注册转换主任(TStringList,
函数(数据:TObject):TListOfStrings
变量
一、 计数:整数;
开始
计数:=TStringList(数据)。计数;
设置长度(结果、计数);
对于I:=0进行计数-1 do
结果[I]:=TStringList(数据)[I];
结束
);
结果:=封送。封送(Self)作为TJSONObject;
最后
元帅,自由;
结束;
结束;
{TTestObjectList}
构造函数tobjectlist.Create;
开始
继承创造;
添加(T.Create);
添加(T.Create);
结束;
函数TTestObjectList.Marshal:TJSonObject;
变量
元帅:TJsonMarshal;
开始
封送处理:=TJSONMarshal.Create(TJSONConverter.Create);
尝试
Marshal.RegisterConverter(TTestObject,
函数(数据:TObject):TObject
开始
结果:=T(数据)。封送处理;
结束
);
结果:=封送。封送(Self)作为TJSONObject;
最后
元帅,自由;
结束;
结束;
主程序;
变量
aTestobj:TTestObject;
列表:对象列表;
aJsonObject:TJsonObject;
开始
aTestObj:=TTestObject.Create;
aJsonObject:=aTestObj.Marshal;
Writeln(aJsonObject.ToString);
书面语;
列表:=TTestObjectList.Create;
aJsonObject:=aList.Marshal;
Writeln(aJsonObject.ToString);
Readln;
结束;
开始
尝试
主要的;
除了
关于E:Exception-do
开始
出口代码:=1;
Writeln(格式('[%s]%s',[E.ClassName,E.Message]);
结束;
结束;
结束。
这里有一个“变通方法”来“修复”Delphi XE2上的问题(我能够复制相同的运行时错误)

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

Marshal := TJSONMarshal.Create(TJSONConverter.Create);
将这两行更改为:

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

解决了这个问题-TOndrej提供的测试应用程序执行时没有错误。

刚刚在XE中尝试了您的代码-我必须承认。它起作用了。我得用它试试更复杂的东西。给我几个小时,我会回来的。我想调查一个更大的项目,看看是否有问题发生。。请原谅我的耽搁。我现在已经在XE2中测试了代码。。。它的失败和我的代码一样????也许XE2中的编组有问题?我是泛型的新手,在类型声明中包含构造函数的方式绝对出色。正因为如此,我愿意接受您的代码作为答案-即使它只在XE中工作:-)问题现在升级到QC#99313。使用来自TOndrej.+1的代码示例(对于该示例):-)。。。我必须承认,使用TJSONMarshal.Create和构造函数是一种习惯。但我不知道它实际上没有。。我不敢相信Embarcadero将其标记为已修复——这是一个解决方法——如果已修复,他们就不会有重载构造函数允许您在自己的实例中传递!或者,在这种特殊情况下,当使用任一构造函数时,对象都应该起作用。我要说的是,还有一个
Marshal := TJSONMarshal.Create;  //use the default constructor - which does the same thing as TJSONConvert.Create already