以下程序导致执行TOmniValue.CreateNamed
时出现错误。
{$APPTYPE CONSOLE}
uses
OtlCommon;
var
Value: TOmniValue;
begin
Value := TOmniValue.CreateNamed([
'a', 42,
'b', 666
]);
Writeln(Value['a'].AsString);
Writeln(Value['b'].AsString);
end.
例外类型Exception
,带有消息:
TOmniValue.CreateNamed:名称类型无效
如果名称长度超过一个字符,则代码运行时没有错误并报告预期的输出。
我的代码有问题,或者库存在问题吗?
答案 0 :(得分:4)
这似乎是图书馆的一个问题。 CreateNamed
的实施是:
constructor TOmniValue.CreateNamed(const values: array of const;
const cppDupConWorkaround: boolean);
var
i : integer;
name: string;
ovc : TOmniValueContainer;
begin
ovc := TOmniValueContainer.Create;
Assert(not Odd(Low(values)));
name := '';
for i := Low(values) to High(values) do begin
with values[i] do begin
if not Odd(i) then
case VType of
vtChar: name := string(VChar);
vtString: name := string(VString^);
vtPChar: name := string(StrPasA(VPChar));
vtAnsiString: name := string(VAnsiString);
vtVariant: name := string(VVariant^);
vtWideString: name := WideString(VWideString);
{$IFDEF UNICODE}
vtUnicodeString: name := string(VUnicodeString);
{$ENDIF UNICODE}
else
raise Exception.Create ('TOmniValue.CreateNamed: invalid name type')
end //case
else
case VType of
vtInteger: ovc.Add(VInteger, name);
vtBoolean: ovc.Add(VBoolean, name);
vtChar: ovc.Add(string(VChar), name);
vtExtended: ovc.Add(VExtended^, name);
vtString: ovc.Add(string(VString^), name);
vtPointer: ovc.Add(VPointer, name);
vtPChar: ovc.Add(string(StrPasA(VPChar)), name);
vtAnsiString: ovc.Add(AnsiString(VAnsiString), name);
vtCurrency: ovc.Add(VCurrency^, name);
vtVariant: ovc.Add(VVariant^, name);
vtObject: ovc.Add(VObject, name);
vtInterface: ovc.Add(IInterface(VInterface), name);
vtWideString: ovc.Add(WideString(VWideString), name);
vtInt64: ovc.Add(VInt64^, name);
{$IFDEF UNICODE}
vtUnicodeString: ovc.Add(string(VUnicodeString), name);
{$ENDIF UNICODE}
else
raise Exception.Create ('TOmniValue.CreateNamed: invalid data type')
end; //case
end; //with
end; //for i
SetAsArray(ovc);
end; { TOmniValue.CreateNamed }
上面两个raise
语句中的第一个引发了异常。该异常用于指示为值提供了无法处理的类型。事实证明,当您指定长度为1的字符串文字时,值的类型为vtWideChar
。事实上,这种类型根本没有处理过。
因此,您可以通过强制调用CreateNamed
来接收字符串而不是单个字符来解决此问题:
Value := TOmniValue.CreateNamed([
string('a'), 42,
string('b'), 666
]);
在我看来,最好将库修改为接受单个字符。它已处理AnsiChar
,我怀疑这是一个简单的遗漏,它不处理WideChar
。我认为代码应该是:
constructor TOmniValue.CreateNamed(const values: array of const;
const cppDupConWorkaround: boolean);
var
i : integer;
name: string;
ovc : TOmniValueContainer;
begin
ovc := TOmniValueContainer.Create;
Assert(not Odd(Low(values)));
name := '';
for i := Low(values) to High(values) do begin
with values[i] do begin
if not Odd(i) then
case VType of
vtChar: name := string(VChar);
vtString: name := string(VString^);
vtPChar: name := string(StrPasA(VPChar));
vtAnsiString: name := string(VAnsiString);
vtVariant: name := string(VVariant^);
vtWideString: name := WideString(VWideString);
vtWideChar: name := string(VWideChar);
{$IFDEF UNICODE}
vtUnicodeString: name := string(VUnicodeString);
{$ENDIF UNICODE}
else
raise Exception.Create ('TOmniValue.CreateNamed: invalid name type')
end //case
else
case VType of
vtInteger: ovc.Add(VInteger, name);
vtBoolean: ovc.Add(VBoolean, name);
vtChar: ovc.Add(string(VChar), name);
vtExtended: ovc.Add(VExtended^, name);
vtString: ovc.Add(string(VString^), name);
vtPointer: ovc.Add(VPointer, name);
vtPChar: ovc.Add(string(StrPasA(VPChar)), name);
vtAnsiString: ovc.Add(AnsiString(VAnsiString), name);
vtCurrency: ovc.Add(VCurrency^, name);
vtVariant: ovc.Add(VVariant^, name);
vtObject: ovc.Add(VObject, name);
vtInterface: ovc.Add(IInterface(VInterface), name);
vtWideString: ovc.Add(WideString(VWideString), name);
vtWideChar: ovc.Add(string(VWideChar), name);
vtInt64: ovc.Add(VInt64^, name);
{$IFDEF UNICODE}
vtUnicodeString: ovc.Add(string(VUnicodeString), name);
{$ENDIF UNICODE}
else
raise Exception.Create ('TOmniValue.CreateNamed: invalid data type')
end; //case
end; //with
end; //for i
SetAsArray(ovc);
end; { TOmniValue.CreateNamed }
报告为:OTL issue #64