你的位置: 首页 > 新闻博客 > 技术博客

Delphi:尽量避免使用'with'语句

2024-03-06 09:40:59

在 Delphi 中使用 with 语句会使您的代码不那么面向未来。

最初,Pascal 中的语句在一定程度上是允许编译器优化的:with

PASCAL 用户手册和报告 – Kathleen Jensen、Niklaus Wirth – Google 图书

with 子句有效地打开了包含指定记录变量的字段标识符的作用域,以便字段标识符可以作为变量标识符出现。(从而为编译器提供了优化限定语句的机会。)

这本 1975 年的书的屏幕截图如下。

Delphi(实际上甚至在 Turbo Pascal 编译器之前)在代码和非代码之间没有可衡量的区别。withwith

但是,调试器仍然不支持,并且还有其他缺点,如下所示。

下面的代码示例只是众多代码示例之一。我之所以展示它,是因为我最近碰到了一些早就应该移植到 Delphi XE3 的代码。

由于我以前被咬过几次,所以没过多久我就找到了原因。with

示例代码 where 的类型是用于编译精细:FIConDataNOTIFYICONDATAW

1
2
3
4
5
6
7
8
9
10
with FIconData do
begin
  cbSize := SizeOf(FIconData);
  Wnd := Self.Handle;
  uID := $DEDB;
  uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
  hIcon := Application.Icon.Handle;
  uCallbackMessage := WM_CAS400NTIcon;
  StrCopy(szTip, PChar(Caption));
end;

好吧,从编译器版本 20 开始,它不再编译了。

原因是_NOTIFYICONDATAW已更改,因为基础 Windows API NOTIFYICONDATA 结构已更改以适应新的 Windows Vista 功能。

但是,由于向后兼容性,在 Windows Vista 之前的 Windows 版本上运行时,无法传递完整的新结构。

因此,这段代码用于计算截至 Delphi 2009 的单元中的正确结构大小:ShellApi

1
2
3
4
5
6
7
8
9
class function _NOTIFYICONDATAW.SizeOf: Integer; static;
begin
  if Win32MajorVersion >= 6 then
    // Size of complete structure
    Result := System.SizeOf(_NOTIFYICONDATAW)
  else
    // Platforms prior to Vista do not recognize the fields guidItem and hBalloonIcon
    Result := System.SizeOf(_NOTIFYICONDATAW) - System.SizeOf(TGUID) - System.SizeOf(Winapi.Windows.HICON);
end;

SizeOf这是一个非常好的名字,但当你使用这个语句时,它会发生冲突。with

添加了其他三个功能。这是四个的完整列表:SizeOf

  • 单元窗口:
    • 类函数 tagNONCLIENTMETRICSA.SizeOf: Integer;
    • 类函数 tagNONCLIENTMETRICSW.SizeOf: Integer;
  • 单位通讯:
    • 类函数 MCHITTESTINFO。SizeOf:整数;
  • 单位 ShellApi:
    • 类函数_NOTIFYICONDATAW。SizeOf:整数;静态的;

你很想重写这样的内容:with

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    with FIconData do
    begin
{$if CompilerVersion >= 20}
      cbSize := SizeOf();
{$else}
      cbSize := SizeOf(FIconData);
{$ifend CompilerVersion >= 20}
      Wnd := Self.Handle;
      uID := $DEDB;
      uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
      hIcon := Application.Icon.Handle;
      uCallbackMessage := WM_CAS400NTIcon;
      StrCopy(szTip, PChar(Caption));
    end;

但实际上你应该像这样重写它,这样你就可以确定每个值来自哪个实体:

1
2
3
4
5
6
7
8
9
10
11
{$if CompilerVersion >= 20}
    FIconData.cbSize := FIconData.SizeOf();
{$else}
    FIconData.cbSize := SizeOf(FIconData);
{$ifend CompilerVersion >= 20}
    FIconData.Wnd := Self.Handle;
    FIconData.uID := $DEDB;
    FIconData.uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
    FIconData.hIcon := Application.Icon.Handle;
    FIconData.uCallbackMessage := WM_CAS400NTIcon;
    StrCopy(FIconData.szTip, PChar(Caption));


QQ在线咨询
售前咨询
0531-66900120
售后服务
13287796906
QQ在线咨询
售前咨询
0531-66900120
售后服务
13287796906