更好地提及: 我正在使用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时,我会遇到同样的问题(或类似的东西)。
欢迎任何建议/想法。
答案 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.