-2

次のプログラムでは、 の実行時にエラーが発生します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: 無効な名前タイプ

名前の長さが 1 文字を超える場合、コードはエラーなしで実行され、期待される出力が報告されます。

私のコードに問題がありますか、それともライブラリに問題がありますか?

4

1 に答える 1

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上記の 2 つのステートメントの最初のステートメントによって発生します。例外は、処理できないタイプの値が指定されたことを示すために使用されます。結局のところ、長さ 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

于 2014-06-02T12:58:28.960 に答える