1

データ型があります

type
TDataTypeId = (DataTypeId_String, DataTypeId_SmallInt, DataTypeId_Integer, DataTypeId_Word,
               DataTypeId_Boolean, DataTypeId_Float, DataTypeId_Currency,
               DataTypeId_BCD, DataTypeId_FmtBCD, DataTypeId_Date,
               DataTypeId_Time, DataTypeId_DateTime, DataTypeId_TimeStamp,
               DataTypeId_Bytes, DataTypeId_VarBytes, DataTypeId_Blob,
               DataTypeId_Memo, DataTypeId_Graphic, DataTypeId_fmtMemo,
               DataTypeId_FixedChar, DataTypeId_WideChar, DataTypeId_LargeInt,
               DataTypeId_Array, DataTypeId_FixedWideChar, DataTypeId_WideMemo);

この型の値の 1 つを含む行を受け取り、この値を返す関数があります。

Function GetType(str: string): TDataTypeId;
var
typeidx: TDataTypeId;
typestr: string;
begin
for typeidx := Low(TDataTypeID) to High(TDataTypeID) do
 begin
  typestr:=GetEnumName(TypeInfo(TDataTypeId),Ord(typeidx));
  typestr:=Copy(typestr, 12, length(typestr)-11);
  //Memo.Lines.Add(typestr+'\n');
  if (AnsiCompareStr(str, typestr)=0) then
     Result:=typeidx
 end;
 end;

その結果、アセンブリがあります

[dcc32 Warning] UnloadProcs.pas(59): W1035 Return value of function 'GetType' might be undefined

警告が発生しなかった関数を変換する方法は?

4

3 に答える 3

5

コンパイラの警告は正確です。True一致が見つからなかったために if ステートメントが に評価されない場合、ループは Result に割り当てられません。そして、関数は値を割り当てずに終了します。

オプション:

  1. Resultループが完了した後、一致が見つからなかったことを示す値を に割り当てます。
  2. ループが完了した後、例外を発生させます。

またexit、割り当てた直後にResult. 答えが見つかったときにループを続けても意味がありません。

この関数を次のように書く可能性があります。

Function GetType(str: string): TDataTypeId;
var
  typestr: string;
begin
  for Result := low(Result) to high(Result) do
  begin
    typestr := GetEnumName(TypeInfo(TDataTypeId),Ord(typeidx));
    typestr := Copy(typestr, 12, length(typestr)-11);
    if AnsiSameStr(str, typestr) then
      exit;
  end;
  raise EEnumNotFound.CreateFmt('Enum not found: %s', [str]);
end; 

Resultループ変数としての変数の使用に注意してください。これは慣用的であり、宣言するローカル変数の数を減らすという利点があります。

を使用すると、おそらく問題をより効果的に解決できることに同意しますがGetEnumValue、慣用的な方法でコンパイラの警告に対処する方法を示したかったのです。

于 2012-12-19T14:14:25.250 に答える
1

このようなループで使用する一般的な方法については、result次のように関数をコーディングできます。

Function GetType(const str: string): TDataTypeId;
var
typestr: string;
begin
 for result := Low(TDataTypeID) to High(TDataTypeID) do
 begin
  typestr:=GetEnumName(TypeInfo(TDataTypeId),Ord(result));
  typestr:=Copy(typestr, 12, length(typestr)-11);
  //Memo.Lines.Add(typestr+'\n');
  if (AnsiCompareStr(str, typestr)=0) then
     exit; // if found, returns result value
 end;
 result := DataTypeId_String; // returns STRING type by default
end;

これは、ループのスコープ外でループ変数を使用できる唯一のケースの 1 つです。生成されたコードは正しく、最適化されています。

専用のTDataTypeIdアイテムのようなものを定義するDataTypeId_Unknownか、見つからない場合は例外を発生させる方がよいと思います。

于 2012-12-19T14:25:54.697 に答える
0

他の人が警告を説明しましたが、ルーチンのより良い実装は次のようになります。

uses
  TypInfo, ConvUtils;

Function GetType(str: string): TDataTypeId;
var idx: Integer;
begin
  idx := GetEnumValue(TypeInfo(TDataTypeId), 'DataTypeId_'+str);
  if(idx <> -1)then Result := TDataTypeId(idx)
  else RaiseConversionError('Unknown typeID name: '+str);
end;

つまり、すべての列挙値をループして文字列として比較する必要はありませんGetEnumValue。代わりに関数を使用してください。

于 2012-12-19T14:21:25.830 に答える