我有一个JSONArray作为参数传递给我的服务器。我有一个由&#34生成的方法生成datasnap客户端类"程序以及何时到达第一个" SetJsonValue"它给我一个访问冲突,这个错误来来往往没有明显的原因。我在局域网中使用了Rest服务器(也使用了http,但尚未使用它进行测试)。有时它会通过重新启动我的计算机/编译器来解决,但有时会持续更长时间。
该方法如下:
if FExecutaInsertCommand = nil then
begin
FExecutaInsertCommand := FConnection.CreateCommand;
FExecutaInsertCommand.RequestType := 'POST';
FExecutaInsertCommand.Text := 'TServerMethods."ExecutaInsert"';
FExecutaInsertCommand.Prepare(TServerMethods_ExecutaInsert);
end;
FExecutaInsertCommand.Parameters[0].Value.SetWideString(database);
FExecutaInsertCommand.Parameters[1].Value.SetWideString(Tabela);
FExecutaInsertCommand.Parameters[2].Value.SetJSONValue(aValores, FInstanceOwner);
FExecutaInsertCommand.Parameters[3].Value.SetJSONValue(aTipos, FInstanceOwner);
FExecutaInsertCommand.Parameters[4].Value.SetInt32(usuario);
FExecutaInsertCommand.Execute(ARequestFilter);
Result := FExecutaInsertCommand.Parameters[5].Value.GetInt32;
从这里调用该方法:
result := DMClient.ServerMethodsClient.ExecutaInsert(banco, Tabela, GeraJSONArray(Registro), GeraJSONArray(GetStrings(Registro.DataType)), CodigoUsuarioLogado);
并且JSONArrays生成如下:
function GeraJSONArray(Valores: TVariantArray) : TJSONArray;
var
i : Integer;
begin
result := TJSONArray.Create;
for i := 0 to Length(Valores.Values) - 1 do
result.Adiciona(Valores.Values[i], Valores.DataType[i]);
end;
function GeraJSONArray(Valores: TArray<String>) : TJSONArray;
var
i : Integer;
begin
result := TJSONArray.Create;
for i := 0 to Length(Valores) - 1 do
result.AddElement(TJSONString.Create(Valores[i]));
end;
JsonArray.Adiciona:
procedure TJSONArrayHelper.Adiciona(valor: variant; DataType: TFieldType);
var
JSONValue : TJSONValue;
begin
if not (VarIsEmpty(valor)) and not (VarIsNull(valor)) then
begin
case DataType of
TFieldType.ftString,
TFieldType.ftMemo,
TFieldType.ftFmtMemo,
TFieldType.ftFixedChar,
TFieldType.ftWideString : JSONValue := TJSONString.Create(valor);
//-----------------------------------------------//
TFieldType.ftSmallint,
TFieldType.ftInteger,
TFieldType.ftWord,
TFieldType.ftFloat,
TFieldType.ftCurrency,
TFieldType.ftAutoInc,
TFieldType.ftLargeint,
TFieldType.ftSingle,
TFieldType.ftBCD : JSONValue := TJSONNumber.Create(valor);
//-----------------------------------------------//
TFieldType.ftDateTime : JSONValue := TJSONString.Create(DateTimeParaString(valor));
end;
end
else
begin
JSONValue := TJSONNull.Create;
end;
if JSONValue <> nil then
AddElement(JSONValue);
end;
参数2生成错误,但参数3不生成,我认为有关Adiciona程序的问题
答案 0 :(得分:1)
在Adiciona
方法中,如果DataType
不是case
语句中列出的任何值,则您的本地JSONValue
变量仍然未初始化。特别要注意的是,变量的默认值是不是 nil - 没有本地对象引用变量将具有的默认值 - 所以在方法结束时检查{{1这是一个无意义的比较。
documentation lists 52 possible TFieldType
values;您的代码只处理15.您可以使用JSONValue <> nil
子句来说明剩下的内容:
else
编译器应该警告您该变量可能未被初始化,尽管该警告所需的分析不可能是完美的,因此编译器可能无法检测到该情况。如果编译器警告您并且您忽略了警告,那么请将此作为教训。
我们可能期望将未初始化的对象引用添加到数组中,这与您观察到的访问冲突异常一致。析构函数将从数组中获取未初始化的值,并尝试在其上调用case DataType of
...
else raise Exception.CreateFmt('Unexpected field type (%d)', [Ord(DataType)]);
。在非对象引用的事物上调用方法可能会导致许多问题;您可以希望的最佳事物就是您现在所看到的,这是一个例外,可以立即告诉您出现问题。 (想想如果程序默默地继续运行会有多糟糕。如果析构函数的GetOwned
调用已经运行并且实际上破坏了程序中的其他内容,谁知道会遇到什么奇怪的问题?)