8

大規模なアプリ (XE3 で正常に動作) を XE4 でコンパイルした後に実行したときにのみ表示される動作をデバッグしようとしています。この問題により、Web.HTTPProd で TPageProducer によって「引用符が解除」された後でも、一部の引用符付き文字列 ("MyString" など) の引用符が保持されるようです。たとえば、この Delphi ソース ユニット Web.HTTPApp から抜粋した以下のコードを考えてみましょう。

procedure ExtractHeaderFields(Separators, _WhiteSpace: TSysCharSet; Content: PChar;
  Strings: TStrings; Decode: Boolean; StripQuotes: Boolean = False);
{$ENDIF NEXTGEN}
var
  Head, Tail: PChar;
  EOS, InQuote, LeadQuote: Boolean;
  QuoteChar: Char;
  ExtractedField: string;
{$IFNDEF NEXTGEN}
  WhiteSpaceWithCRLF: TSysCharSet;
  SeparatorsWithCRLF: TSysCharSet;
{$ENDIF !NEXTGEN}

  function DoStripQuotes(const S: string): string;
  var
    I: Integer;
    InStripQuote: Boolean;
    StripQuoteChar: Char;
  begin
    Result := S;
    InStripQuote := False;
    StripQuoteChar := #0;
    if StripQuotes then
    begin
      for I := Result.Length - 1 downto 0 do
        if Result.Chars[I].IsInArray(['''', '"']) then
          if InStripQuote and (StripQuoteChar = Result.Chars[I]) then
          begin
            Result.Remove(I, 1);
            InStripQuote := False;
          end
          else if not InStripQuote then
          begin
            StripQuoteChar := Result.Chars[I];
            InStripQuote := True;
            Result.Remove(I, 1);
          end
    end;
  end;

TPageProducer を使用するときにこれが呼び出されるのを確認し、適切なソース文字列が上記の ExtractHeaderFields ルーチンに入り、次に「DoStripQuotes」関数に入ることがわかります。DoStripQuotes にステップインして 'Result' を見ると、Result.Remove が呼び出されても (引用符を削除するために) 変更されないことがわかります。この「DoStripQuotes」ルーチンを単純なテスト アプリに使用すると、コンパイルされず、「Result.anything」が許可されていないことがわかります。「文字列」として定義されていますが、結果はWeb.HTTPProdのコンテキストでは別のタイプの文字列でなければならないと思います。

それで、これは私が聞いた「不変の文字列」と関係があるのではないかと考え始めました。私はそれについてこのSOの質問を読みました。要点はわかりましたが、より実用的なアドバイスを行うことができました。

具体的には、次の質問に対する回答を希望します。

  1. 表記法 Result.Length が許可されている場合、「結果」はどのタイプの「文字列」ですか?
  2. ユニットに「XE3」互換性を使用するようにコンパイラに指示する方法はありますか? (これにより、問題の発生場所を確認できる場合があります)。{$ZEROBASEDSTRINGS ON} / OFF を試してみましたが、これはさらに混乱を引き起こしているようで、何をしているのかわかりません!

助けてくれてありがとう。

LATER EDIT:以下の受け入れられた回答に記載されているように、これは VCL ユニット Web.HTTPApp.pas のバグであり、「Result := Result.Remove(I,1)」を 2645 行付近の 2 か所で読み、「Result.削除(I,1)"

4

1 に答える 1

9

表記法 Result.Length が許可されている場合、「結果」はどのタイプの「文字列」ですか?

それ以来、あなたが使ってきたのはstring、 にエイリアスされた同じ古いです。違いは、このコードが新しいレコード ヘルパー (具体的には) を使用することです。これが、文字列変数で表記法を使用できるようにするものです。UnicodeStringDelphi 2009SysUtils.TStringHelper.

ユニットに「XE3」互換性を使用するようにコンパイラに指示する方法はありますか?

いいえ。問題のコードはライブラリ ユニットであり、特定のモードでコンパイルされるように設計されています。さらに、RTL/VCL を自分でコンパイルしない限り、簡単に再コンパイルすることはできません。そのようなモードがあったとしても、コードが単純に間違っているため、役に立ちません (以下を参照)。モードを切り替えても、この特定のコードを修正することはできません。

これは、私が聞いたイミュータブル文字列と関係があるのではないかと思います。

そうではありません。不変の文字列を備えた Delphi コンパイラはまだありません。不変文字列の概念は、将来の変更として浮かんできたものです。また、変更が行われる場合は、最初にモバイル コンパイラで行われることを期待してください。


問題は実際には、投稿したコードのかなり単純なバグであり、明らかにテストがまったく行われていません。の使い方Removeが間違っています。そのメソッドは、文字列をその場で変更しません。代わりに、文字が削除された新しい文字列を返します。コードは次のようになります。

Result := Result.Remove(I, 1);

コーディングした開発者ExtractHeaderFieldsがこの間違いを犯したのは、文字列ヘルパー コードを設計した人がRemoveメソッドの名前を間違っていたからです。は動詞なのでRemove、その場で動作することが期待されます。このメソッドのように、サブジェクトを変更せずに新しいインスタンスを返すメソッドには、名詞である名前を付ける必要があります。したがって、このメソッドは のような名前にする必要がありますRemnants。RTL 設計者が .net 命名をコピーしたように見えますが、同じ欠陥も存在します。

QC レポートが存在しない場合は、提出する必要があります。XE4 アップデート 1 がリリースされたことを知っています。修正が含まれている可能性があります。

私が見ているように、あなたの他のオプションは次のとおりです。

  1. XE4 が十分にデバッグされるまで、XE3 を使用してください。
  2. ユニットのコピーをWeb.HTTPAppプロジェクトに含めて、自分でバグを修正してください。
于 2013-06-12T09:12:48.787 に答える