Show/Hide Toolbars

XSharp

用途

声明一种为特定实例变量赋值的方法。

语法

 [Attributes] [Modifiers] ASSIGN <idVar>

 [([<idParam> [AS | REF <idType>] [, ...])]

 [AS <idType>] [<idConvention>]

 [CLASS <idClass>]

 [=> <expression>]

 CRLF

 [<Body>]

 [END ACCESS]

参数

Attributes一个可选的特性列表,用于描述实体的元信息,例如在 MsTest 类库中包含测试的方法/函数上的 [TestMethod] 属性。请注意,当特性写在关键字上方的行时,特性必须在同一行或以分号结尾。

 

Modifiers一个可选的修饰符列表,用于指定实体的可见性或范围,例如:PUBLIC, PROTECTED, HIDDEN, INTERNAL, SEALED, ABSTRACT 或 STATIC.

 

<idVar>一个有效的实例变量标识符名称,您正在为其定义 assign 方法。 与其他方法一样,assign 方法也是实体;不过,系统为它们使用了独特的命名方案,以防止与其他实体名称相冲突。 在一个类中,ASSIGN 方法的名称必须是唯一的,但也可以与应用程序中的其他实体名称相同。

 

TypeParameters这适用于具有泛型类型参数的方法。这类似于 `<T>`,用于具有一个名为 T 的类型参数的方法。通常,参数列表中的一个参数也是类型 T。
<idParam>参数变量。 以这种方式指定的变量会自动声明为局部变量。 这些变量也称为形参(形式参数),用于接收调用实体时传递的参数。

 

AS | REF | OUT | IN <idType>指定参数变量的数据类型(称为强类型)。 AS 表示参数必须通过值传递,REF 表示参数必须通过带 @ 操作符的引用传递。OUT 是一种特殊的 REF 参数,不必在调用前赋值,必须在实体内部赋值。IN 参数作为 READONLY 引用传递。
列表中的最后一个参数也可以声明为 PARAMS <idType>[] ,这将告诉编译器函数/方法可以接收零个或多个可选参数。
使用 CLIPPER 调用约定的函数或方法将被编译为一个带有单个参数的函数,该参数被声明为 Args PARAMS USUAL[] 。
AS <idType>指定数据类型。如果省略,编译器依据编译选项来决定数据类型,或者是 USUAL,或者是由编译器自行决定。

 

TypeParameterConstraints在这里,您可以为类型参数指定约束,例如 WHERE T IS SomeName 或 WHERE T IS New。
<idConvention>指定此实体的调用约定。 <idConvention> 必须是以下内容之一:

o        CLIPPER

o        STRICT

o        PASCAL

o        CALLBACK

o        THISCALL

大多数 调用约定 仅用于向后兼容。
但是,存在两个例外情况:
1. CLIPPER 声明方法具有未类型化参数。通常只有没有声明参数的方法才需要这样做。否则,编译器在检测到未类型化参数时将假定使用 CLIPPER 调用约定。
2. 外部 DLL 的方法和函数可以使用 STRICT、PASCAL、 CALLBACK 调用约定。

 

 

CLASS <idClass>该方法所属的类。对于在 CLASS ... END CLASS 结构之外声明的实体,必须使用该子句。

 

=> <Expression>替代实体多行正文(body)的单一表达式。不能与正文(body)一起编译

 

<Body>构成此主体代码的程序语句。
<Body> 可以包含一个或多个 RETURN 语句,以将控制权返回给调用例程,并作为函数的返回值。如果未指定 RETURN 语句,当函数定义结束时,控制权将返回给调用例程,并且函数将根据指定的返回值数据类型返回一个默认值(如果返回值没有强类型,则返回 NIL)。
不能与表达式主体(Expression Body)结合使用。
END ASSIGN可选的结束语,表示 ASSIGN 实体的结束。

描述

ASSIGN 声明了一个特殊的方法,称为赋值方法,每次为命名的实例变量赋值时都会自动执行(例如,<idVar> := <uValue>)。 赋值操作符右侧的值作为参数传递给 ASSIGN 方法。

 

在 CLASS 声明中可以定义四种类型的实例变量。 除了 EXPORT 之外,所有这些都被称为非导出(non-exported)实例变量,因为它们不能直接从外部(即类之外)访问。

 

例如,如果要在函数中为非导出变量(non-exported)赋值,就必须使用方法。 这意味着对实例变量赋值的接口取决于类的实现。 ASSIGN 方法为所有实例变量的赋值提供了通用语法。 与 ACCESS 方法(参见本指南中的 ACCESS 语句)结合使用,ASSIGN 方法可让你在应用程序中执行封装原则,同时保持稳定的类接口。

 

下面的示例说明了如何使用传统方法为非导出实例变量赋值。 请注意在 UseClass() 中为实例变量 x 和 y 赋值的不同之处:

CLASS Test
 EXPORT x
 INSTANCE y
 
METHOD PutValueY(nPut) CLASS Test
 y := nPut
 RETURN y
 
FUNCTION UseClass()
 LOCAL oTest AS Test
 oTest := Test{}
 ? oTest:x := 100
 ? oTest:PutValueY(100)        // 使用常规方法

如果将该方法替换为 assign 方法(如下所示),对两个变量赋值的语法是相同的:

ASSIGN y(nPut) CLASS Test
 y := nPut
 RETURN y

FUNCTION UseClass()
 LOCAL oTest AS Test
 oTest := Test{}
 ? oTest:x := 100
 ? oTest:y := 100                // 使用 ASSIGN 方法

注意:ASSIGN 方法一般应返回实际赋值,以确保它所代表的假定变量实际上像一个变量--从技术上讲,赋值是关联的。 这样就可以像普通变量一样进行链式赋值(例如,Var2 := oTest1:y := oTest1:x := Var1 := 10000)。

 

非导出(non-exported)变量分为三类,每一类都有自己的属性(详见本指南中的 CLASS 语句):

               INSTANCE

               PROTECT

               HIDDEN

 

INSTANCE 变量是专门为 ASSIGN 和 ACCESS 方法而设计的,这也是其后期绑定的主要原因。 通过定义与 INSTANCE 变量同名的赋值方法,你可以有效地覆盖变量,使所有赋值引用(包括外部和内部引用)都调用 ASSIGN 方法。 例外情况是,在 ASSIGN(或 ACCESS)方法中,同名的实例变量会引用该变量--否则,你将一事无成。

 

您还可以将 PROTECT 和 HIDDEN 变量与 assign 方法结合使用。 通过定义与 PROTECT 或 HIDDEN 变量同名的 ASSIGN 方法,你可以使用与类内部相同的语法在外部对变量进行赋值。 然而,由于提前绑定的原因,内部引用总是直接引用变量。

 

当然,你不必给 ASSIGN 方法和实例变量起相同的名字。 这样做只是为了方便。 当您通过赋值访问 <idVar> 时,是由方法本身决定使用哪个实例变量名。 因此,对于 PROTECT/HIDDEN 变量,可以使用不同名称的 ASSIGN 方法。 例如

CLASS Person
 PROTECT Name_Protected
 
ASSIGN Name(cPutName) CLASS Person
 Name_Protected := cPutName
 RETURN Name_Protected

与非导出(non-exported)变量和 ACCESS 方法相比,EXPORT 变量使用起来更快、更方便,但使用 EXPORT 变量却有悖于封装性,而封装性正是为提高应用程序的完整性而应努力实现的。 使用 ACCESS 方法和 ASSIGN 方法,你可以在应用程序原型设计的早期阶段使用 EXPORT 变量,之后在不改变类接口的情况下使用方法保护变量。

 

ACCESS 是 METHOD 的一种特例,除了调用方式(即不带参数,就像实例变量一样)外,其行为与其他方法相同。 更多详情,请参阅本指南中的 METHOD 语句

 

注意:ACCESS 方法的内部引用如果没有相应的常规 INSTANCE 变量(例如,虚(拟)变量或对不同名称的 HIDDEN 或 PROTECT 变量的公共访问),则必须使用 SELF: 前缀。 内部引用是指来自类或其子类方法内部的引用。 如果系统没有找到实例变量,则会假定是内存变量(这可能会导致编译器出错,具体取决于编译器设置中是否选择了 "允许未声明变量"),除非使用了 SELF:,否则系统不会尝试将引用识别为 ACCESS 方法。

强类型方法

 

除了 XSharp 的非类型化方法实现外,现在还支持方法参数和返回值的强类型,这为您提供了一种可以获得高度稳定代码的机制。提供的类型信息使编译器能够执行必要的类型检查,从而保证更高的代码质量稳定性。

 

使用强类型方法的另一个好处是性能。强类型方法的实现假定当程序员使用强类型消息时,编译器可以有效地为相应的方法调用执行早期绑定(early binding)。由于这种实现,强类型方法的调用比相应的非类型化方法调用稍快。然而,这些优势是以失去非类型方法所提供的灵活性为代价的。

 

因此,重要的是要记住,在继承链中交替使用特定方法的强类型和非类型版本既不允许也不可能。

 

XSharp 允许对 METHODs、ACCESSes 和 ASSIGNs 进行强类型化。程序员通过以下两个步骤完成 XSharp 中强类型方法的指定:

 

1.在其相应的类中进行强类型方法的强制声明。
该声明负责在 XSharp 用于调用强类型方法的所谓虚拟表中声明方法的顺序。在子类中重新声明方法是不允许的,因为这会导致编译器的歧义。

 

2.定义强类型方法。
与强类型函数不同,方法类型化要求对方法参数、方法返回值进行强类型化,并指定有效的调用约定。
以下调用约定对强类型方法有效:STRICT、PASCAL 或 CALLBACK。

示例

下面的示例使用 ASSIGN 建立了一个公共协议,用于对 INSTANCE 变量进行赋值:

CLASS Rectangle
 INSTANCE Length, Height AS INT
 
ASSIGN Length(nX) CLASS Rectangle
 Length := nX
 RETURN Length
 
ASSIGN Height(nY) CLASS Rectangle
 Height := nY
 RETURN Height
 
FUNCTION UseClass()
 LOCAL oShape AS Rectangle
 oShape := Rectangle{}
 oShape:Length := 3
 oShape:Height := 4a

参见

ACCESS, CLASS, METHOD, PROPERTY