10

Raymond Chen 今天的一篇博客文章让我意识到我遇到的问题的优雅解决方案。

可以使各种shell函数,而不是全部采用ITEM­ID­LIST结构,只接受:

  • ITEM­ID_CHILD
  • ID­LIST_RELATIVE
  • ID­LIST_ABSOLUTE
  • ITEM­ID_CHILD_ARRAY

结构。这些结构都是相同的,但现在您可以在编译器级别强制执行概念类型。

回到德尔福

我有一组功能:

  • 有些走一条路:(例如C:\Users\Ian\Desktop\AllisonAngel.jpg
  • 有些取文件名:(例如AllisonAngel.jpg
  • 有些只拿一个文件夹:(例如C:\Users\Ian\Desktop

现在它们都被声明为string,例如:

 function GetFilenames(Folder: string; ...): ...
 function IsValidBatchFilename(Path: string): ...
 function GetReportType(Filename: string): ...

我必须相信我传递的是正确的东西;而且我相信开发人员(例如)知道以下之间的区别:

  • 一条路径
  • 文件
  • 和一个文件夹

我想更改函数以使用“键入”字符串:

 function GetFilenames(Folder: TFolderOnly; ...): ...
 function IsValidBatchFilename(Path: TFullPath): ...
 function GetReportType(Filename: TFilenameOnly): ...

在哪里:

type
   TFullPath = type string;
   TFolderOnly = type string;
   TFilenameOnly = type string;

除了没有实际的打字发生:

var
   dropFolder: string;
begin
   dropFolder := GetDropFolderPath(LCT);

   GetFilenames(dropFolder); <-- no compile error

end;

我想要的是“不同”类型的字符串;也就是说string,它是以长度为前缀、引用计数、以空值结尾的。

4

3 回答 3

9

您可以使用高级记录来完成此操作。例如,你可以做

type
  TFileName = record
    FFileName: string;
  public
    class function IsValidFileName(const S: string): boolean; static;
    class operator Implicit(const S: string): TFileName;
    class operator Implicit(const S: TFileName): string;
  end;

implementation

class function TFileName.IsValidFileName(const S: string): boolean;
begin
  result := true {TODO};
end;

class operator TFileName.Implicit(const S: string): TFileName;
begin
  if IsValidFileName(S) then
    result.FFileName := S
  else
    raise Exception.CreateFmt('Invalid file name: "%s"', [S]);
end;

class operator TFileName.Implicit(const S: TFileName): string;
begin
  result := S.FFileName;
end;

同样对于TPathTFolder。优点:

  • 期望的函数TPath将不接受 a TFileName(或其他组合)。
  • 您仍然可以分配TPath到/从常规字符串。如果从字符串转换为 a TPath,您将自动检查字符串以查看它是否包含有效路径。
  • 或者,您可以通过编写更多类运算符来指定如何将 aTPath分配给 a TFileName(或其他组合) 。Implicit
于 2013-01-24T18:24:23.117 回答
8

为每种字符串类型创建不同的记录类型。不同的记录类型不是赋值兼容的,即使字符串类型是兼容的。

type
  TFullPath = record value: string end;
  TFolderOnly = record value: string end;

Chen 的文章将新的 shell 功能与创建不同句柄类型的经典 STRICT 宏进行了比较,我记得,声明不同的结构正是 STRICT 宏的工作方式。

于 2013-01-24T18:19:05.303 回答
2

使用 Delphi 处理基本类型的方式,我很高兴这是“你无法从这里到达那里”的情况。

您的字符串类型声明都将满足 Delphi 的类型兼容性和赋值兼容性规则。var他们将限制的是带有参数的过程声明。如果您将函数声明更改为 var 参数而不是引用或值参数,您将在最后一个示例中收到编译错误。

说了这么多,反正都是没用的。您仍然无法确保输入只是一个文件名,即使是TFilenameOnly类型,并且无论如何都必须在您的过程中测试内容。

于 2013-01-24T18:19:16.907 回答