TDictionary通过DataSnap崩溃,FComparer是零

时间:2018-04-03 16:41:23

标签: delphi delphi-10.1-berlin datasnap

我在DataSnap客户端中遇到字典崩溃,因为它的FComparer在某种程度上是零。

服务器端代码:

TColorNames = TDictionary<integer, string>;

function TServerMethods.DictionaryTest: TColorNames;
begin
  result := TColorNames.Create;
  result.Add (1, 'Red');
  result.Add (2, 'Blue');
end;

客户端代码:

procedure TformClientMain.FetchColors;
var
  Colors: TColorNames;
begin
  Colors := easServer.DictionaryTest;
  if Colors.Items[1]<>'Red'
     then ShowMessage('Not red');
end;

Colors.Items[1]崩溃(以及需要FComparer的其他功能)。当函数尝试访问FComparer时,崩溃发生在System.Generics.Collections中。

function TDictionary<TKey,TValue>.Hash(const Key: TKey): Integer;

我确实收到了列表中的所有数据,只需使用for color in Colors.Values do ShowMessage(Color);循环播放它就可以了。

watch screenshot on client side

当我使用TColorNames.Create创建字典实例时,在客户端或服务器端,FComparer有一个值,并且这些问题不存在。我在字典构造函数中放置断点并在datasnap调用期间跟踪代码 - FComparer总是获取一个值。

我(或德尔福)做错了什么?

1 个答案:

答案 0 :(得分:5)

“德尔福做错了什么”的答案是:

DataSnap使用单位TJsonMarshal中的TJsonUnmarshalData.DBXJSONReflect。在解组时,通过调用无参数构造函数创建TDictionary<X,Y>的实例。这里的无参数构造函数是直接从TObject继承的构造函数。

时,键入TDictionary<X, Y>.Create();,你正在使用默认参数(Create(ACapacity: Integer = 0);)调用“正确”的构造函数。但是,TJsonUnmarshall类没有,因为它正在寻找实际上没有参数的构造函数。您通常调用的那个有一个参数,即使您不必通过它。

我不知道DataSnap是如何工作的,但你应该能够将自定义编组和解组器传递给序列化。

由于Embarcadero已将我所知道的所有错误报告(example)关闭为“按预期工作”,因此可以安全地认为通用收藏品不应来回编组。你可能应该恢复数组。

以下是重现的最小代码:

unit Unit1;

interface

uses
    System.Generics.Collections,
    System.JSON,
    Data.DBXJSONReflect;

type
    TColorNames = TDictionary<Integer, String>;

procedure p();

implementation

procedure p();
var
    original: TColorNames;
    marshaller: TJSONMarshal;
    unmarshaller: TJSONUnMarshal;
    asJson: TJsonValue;
    marshalledBack: TColorNames;
begin
    original := TColorNames.Create();

    marshaller := TJsonMarshal.Create();
    asJson := marshaller.Marshal(original);

    unmarshaller := TJSONUnMarshal.Create();
    marshalledBack := unmarshaller.Unmarshal(asJson) as TColorNames;

    marshalledBack.Add(0, ''); // << will crash because FComparer is nil
end;

end.