-2

不幸的是,RTL 源代码中没有确切的Assign签名,我尝试猜测,例如:

const
  Assign: procedure (var F; const FileName: string) = System.Assign;
  { or }
  Assign: function (var F; const FileName: string): Integer = System.Assign;
  { also I tried "internal" one from _AssignFile }

没有产生任何积极的结果,并且编译器拒绝将此持续表达式视为程序并抱怨右值E2029 '(' expected but ';' found))。

那么,我应该使用哪种类型来准确匹配 Delphi RTL?

4

3 回答 3

4

Assign是 Delphi 的一种语言残余,其起源可追溯到原始的 Turbo Pascal 语法。早在函数重载被添加到语言语法之前,早在 RTL 的文本文件和“类型文件”内部数据结构被记录之前,Assign.

Assign是一个使用起来足够简单的过程,但是当您查看它必须做什么时,您会发现如果没有某种编译器魔法,它几乎是不可能实现的。File of TFoo创建一个与 . 不同且不兼容的文件类型File of Integer。然而,两者都可以作为第一个参数传递给Assign.

今天,您可能可以Assign使用文件参数的泛型类型参数来实现。泛型类型将符合传入变量的类型。这很好,但我们需要一种方法来将类型化文件变量与字符串文件名相关联 25 年前,泛型被添加到混合中。

Assign是编译器内在函数。这意味着它位于 Delphi/Pascal 语法空间之外。Assign本质上是一个符合类型的过程,它不能用强类型的 Delphi/Pascal 语言来表示(没有现代和复杂的语言扩展,例如泛型类型)。它不是无类型的,也不是动态类型的,因为实际参数类型是在编译时完全确定的。

您不能获取Assign函数的地址。即使您可以,因为它是无定形的,您也无法定义一个准确表示所有可能调用签名的过程类型。

编译器魔术函数存在于语言之外,以处理无法用当时可用的语法轻松表示的任务。Assign是一个例子。Writeln() 是另一个。

于 2013-04-15T19:01:33.957 回答
2

System.Assign是一个内在函数。它的官方文档是完全没有希望的。它说:

function Assign(var F: File; FileName: String; [CodePage: Word]): Integer; overload;
function Assign(var F: File; FileName: String; [CodePage: Word]): Integer; overload;
function Assign(var F: File; FileName: String; [CodePage: Word]): Integer; overload;

我只能猜测为什么文档生成器无法处理此功能。但是这三个相同的重载显然是假的。它不是一个函数,而是一个过程。

不管。因为它是内在的,所以不能将它分配给函数指针。解决方案是将其包装在您自己的功能中。

procedure MyAssign(var F: File; const FileName: string);
begin
  Result := System.Assign(F, FileName);
end;

然后,您可以将该函数分配给过程类型的变量或常量。

const
  AssignProc: procedure(var F: File; const FileName: string) = MyAssign;

的另一个变体Assign采用指定代码页的第三个参数,以Word. Assign如果第一个参数是 a ,则只能调用该函数TextFile

所以,内在函数本身就是一条定律。

请注意,文档确实声明Assign不应再使用。相反,您应该使用AssignFile. 请注意,文档再好不过了!

于 2013-04-15T16:10:31.313 回答
0

如果要打开 System.pas 文件并读取它,在 XE2 中您有这些内部程序:

function _AssignFile(var t: TFileRec; const s: PChar): Integer;
function _AssignText(var t: TTextRec; const s: PChar; const CP: word): Integer;

而且我认为您没有任何名称中没有下划线的全局稳定过程-列出的那些是Delphi编译器内部结构,例如不可见的过程,它们在您声明字符串或dynarray变量时被秘密调用。

http://en.wikipedia.org/wiki/Intrinsic_function

就像许多_Write0LString执行通常的 WriteLn 调用的过程一样。

因此,您必须创建一个包装器函数,该函数将调用AssignFile包装器的引用并将其放入变量中;

但是,您没有在 Delphi 版本中添加标签,并且不同的版本可能对内在函数有不同的声明。因此,请查看您的特定 Delphi 的来源。

另外,你为什么需要它?我记得我做了这样的事情TurboPascal 5.5来制作基于字符串的文件 - 让WriteLn行为像 C sprintf。但是,当您可以使用它时,为什么在现代 Delphi 中需要它TStream呢?

于 2013-04-15T14:12:57.620 回答