case语句中未初始化的变量

时间:2017-01-19 09:14:25

标签: delphi delphi-xe6

每当我使用以下结构时,我仍然无法弄清楚如何摆脱有关未初始化变量的警告,即使我知道这种情况永远不会发生。

long list of user ids which can be queried for currently authenticated user, if this user in department b, than here will be list of user ids in departments B and C, task has no connection to department, only to user
  

W1036变量' lNumber'可能尚未初始化

我找到了3个解决方案,但我不喜欢它们中的任何一个。特别是有更多的变量或陈述。有没有其他方法可以避免这种情况?

  1. 使用TCustomEnum = (ceValue1, ceValue2, ceValue3); function DoSomething(LI_Enum: TCustomEnum): Integer; var lNumber : Integer; begin case LI_Enum of ceValue1 : lNumber := 1; ceValue2 : lNumber := 2; ceValue3 : lNumber := 3; end; Result := 2 * lNumber; end; {$WARN USE_BEFORE_DEF OFF}
  2. 换行功能
  3. 在每个案例陈述中,使用{$WARN USE_BEFORE_DEF ON}并在开头使用else Exit;
  4. 初始化每个变量,尽管该值将永远不会使用

2 个答案:

答案 0 :(得分:6)

通过执行以下操作

String temptime= "1715UTC";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HHmm");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date myDate = simpleDateFormat.parse(temptime);        
long time= Long.toString(myDate.getTime()); 

也许是一个更好的异常文本,甚至根本不会引发异常(并为lNumber分配不同的值),但是提出异常确实有一个好处,例如,如果你想要在六个月之后添加新的异常案件价值。

修改

关键在于编译器是正确的。枚举的基础结构是某种形式的(无符号)整数,因此枚举完全有可能包含非法值,例如27。在实践中有很多方法可以产生。因此,如果您正在编写完整的代码,则需要满足这种可能性。编译器只是警告你,你没有提供这种可能性。

答案 1 :(得分:3)

我发现这个编译器警告有点令人失望。毕竟,编译器肯定可以检测到您已经涵盖了枚举类型的所有可能值。我不相信你应该担心你在枚举类型中加入了一个无效的序数,如果确实这就是这个警告背后的想法。

无论如何,我个人使用以下帮助方法来解决这个问题:

procedure RaiseAssertionFailed; overload;
procedure RaiseAssertionFailed(var v1); overload;
procedure RaiseAssertionFailed(var v1,v2); overload;

....

procedure DoRaiseAssertionFailed;
begin
  raise EAssertionFailed.CreateFmt(
    'A critical error has occurred:'+ sLineBreak + sLineBreak +
    '      Assertion failed at %p.'+ sLineBreak + sLineBreak +
    'In order to avoid invalid results or data corruption please close the program and report '+
    'the above error code along with any other information relating to this problem.',
    [ReturnAddress]
  ) at ReturnAddress;
end;

procedure RaiseAssertionFailed;
asm
  JMP    DoRaiseAssertionFailed;
end;

procedure RaiseAssertionFailed(var v1);
asm
  JMP    DoRaiseAssertionFailed;
end;

procedure RaiseAssertionFailed(var v1,v2);
asm
  JMP    DoRaiseAssertionFailed;
end;

您的代码将成为:

function DoSomething(LI_Enum: TCustomEnum): Integer;
var
  lNumber : Integer;
begin
  case LI_Enum of
    ceValue1 : lNumber := 1;
    ceValue2 : lNumber := 2;
    ceValue3 : lNumber := 3;
  else
    RaiseAssertionFailed(lNumber);
  end;
  Result := 2 * lNumber;
end;

这与@Dsm概述的方法非常相似。如果使用该方法,则编译器可以看到您正在引发异常,并且知道不需要初始化lNumber

我更喜欢将异常的引发包装到共享函数中。这样我就不需要一次又一次地写出相同的错误信息。适用DRY原则。

但是,如果执行此操作并将加注移动到共享函数中,则编译器无法确定该函数是否会引发异常。因此,无类型的var参数。这允许您变量标记为可能被修改,因此禁止编译器警告。

另一种方法是声明一个在其无参数构造函数中提供文本的异常类。

type
  EInternalError = class(Exception)
  public
    constructor Create;
  end;

constructor EInternalError.Create;
begin
  inherited Create(
    '...' // your text goes here
  );
end;

然后您的代码变为:

function DoSomething(LI_Enum: TCustomEnum): Integer;
var
  lNumber : Integer;
begin
  case LI_Enum of
    ceValue1 : lNumber := 1;
    ceValue2 : lNumber := 2;
    ceValue3 : lNumber := 3;
  else
    raise EInternalError.Create;
  end;
  Result := 2 * lNumber;
end;