Delphi - 当单位名称与 属性 名称相同时如何解决冲突?
Delphi - How do you resolve a conflict when a unit name is the same as a property name?
下面这个简单的例子是我试图解决冲突的一个问题的浓缩,在这个冲突中我有一个与 VCL 成员同名的枚举类型成员。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TSomeType = (
alNone,
alSome,
alMany) ;
procedure TForm1.FormCreate(Sender: TObject);
begin
Self.Align := alNone ; // 1. type mismatch
Self.Align := Controls.alNone ; // 2. "Controls" is also a property of TForm
end ;
end.
- 第一次赋值失败,因为编译器认为
alNone
是我声明的,而不是 Controls.pas
中定义的 TAlign
成员。
- 第二个失败,因为它用
Controls
表示那个名字的 TForm
属性。
我知道有很多方法可以解决这个问题(重命名 alNone
成员是最简单的),但我很好奇是否有一种方法可以限定对 属性 的引用单元名称 与当前范围内的标识符冲突的另一个单元。
使用类型名称对其进行限定:
TAlign.alNone
写这篇文章的时候我还没有意识到编译器版本是相关的。此语法仅在 Delphi 2010 或 XE 中可用。那里的答案不适合标记版本 Delphi 2007。Deltics 的答案涵盖了更多细节。
正如 David 的回答所暗示的那样,对于枚举类型或其他可以使用类型来限定所涉及的标识符的情况,那么您当然可以根据需要简单地使用类型名称:
someAlign := TAlign.alNone;
someMyType := TMyType.alNone;
枚举的这种使用被称为“scoped enums”,并且在旧版本的 Delphi 编译器中不受支持。我相信 XE2 可能是在它被引入的时候。当然,这是默认情况下强制以这种方式强制枚举范围的版本。
尽管可以通过编译器指令将其关闭。关闭时,您仍然可以使用范围枚举,但您不需要。
在支持此功能的版本中,您必须限定在启用此功能时定义的任何枚举。当使用关闭时定义的枚举时,您可以选择是否质量。
type
{$SCOPEDENUMS ON}
TFoo = (Black, White); // MUST qualify: eg. "TFoo.Black"
{$SCOPEDENUMS OFF}
TBar = (Black, White); // MAY qualify or not if/as needed
对于没有作用域枚举支持的旧版本 Delphi,或者在标识符 不是 枚举成员并且不能通过类型限定的情况下 - 例如如果您的标识符与某些 unit 级标识符冲突(例如 mrOk
,在 Controls 中),那么您需要一点点更多工作,但不多。
在这些情况下,只需定义一个新常量来为另一个单元中的常量创建一个明确的"local alias",并在单元名称明确的地方引入它。类似于:
type
TMyResult = (
mrOk,
mrFailed) ;
const
Controls_mrOk = Controls.mrOk; // mrOk is a const, not an enum member
下面这个简单的例子是我试图解决冲突的一个问题的浓缩,在这个冲突中我有一个与 VCL 成员同名的枚举类型成员。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TSomeType = (
alNone,
alSome,
alMany) ;
procedure TForm1.FormCreate(Sender: TObject);
begin
Self.Align := alNone ; // 1. type mismatch
Self.Align := Controls.alNone ; // 2. "Controls" is also a property of TForm
end ;
end.
- 第一次赋值失败,因为编译器认为
alNone
是我声明的,而不是Controls.pas
中定义的TAlign
成员。 - 第二个失败,因为它用
Controls
表示那个名字的TForm
属性。
我知道有很多方法可以解决这个问题(重命名 alNone
成员是最简单的),但我很好奇是否有一种方法可以限定对 属性 的引用单元名称 与当前范围内的标识符冲突的另一个单元。
使用类型名称对其进行限定:
TAlign.alNone
写这篇文章的时候我还没有意识到编译器版本是相关的。此语法仅在 Delphi 2010 或 XE 中可用。那里的答案不适合标记版本 Delphi 2007。Deltics 的答案涵盖了更多细节。
正如 David 的回答所暗示的那样,对于枚举类型或其他可以使用类型来限定所涉及的标识符的情况,那么您当然可以根据需要简单地使用类型名称:
someAlign := TAlign.alNone;
someMyType := TMyType.alNone;
枚举的这种使用被称为“scoped enums”,并且在旧版本的 Delphi 编译器中不受支持。我相信 XE2 可能是在它被引入的时候。当然,这是默认情况下强制以这种方式强制枚举范围的版本。
尽管可以通过编译器指令将其关闭。关闭时,您仍然可以使用范围枚举,但您不需要。
在支持此功能的版本中,您必须限定在启用此功能时定义的任何枚举。当使用关闭时定义的枚举时,您可以选择是否质量。
type
{$SCOPEDENUMS ON}
TFoo = (Black, White); // MUST qualify: eg. "TFoo.Black"
{$SCOPEDENUMS OFF}
TBar = (Black, White); // MAY qualify or not if/as needed
对于没有作用域枚举支持的旧版本 Delphi,或者在标识符 不是 枚举成员并且不能通过类型限定的情况下 - 例如如果您的标识符与某些 unit 级标识符冲突(例如 mrOk
,在 Controls 中),那么您需要一点点更多工作,但不多。
在这些情况下,只需定义一个新常量来为另一个单元中的常量创建一个明确的"local alias",并在单元名称明确的地方引入它。类似于:
type
TMyResult = (
mrOk,
mrFailed) ;
const
Controls_mrOk = Controls.mrOk; // mrOk is a const, not an enum member