Caché Objects | 第八章 | 定义和调用方法

方法是由类定义的可执行元素。Caché 支持两种类型的方法:实例方法类方法实例方法是从类的特定实例调用的,通常执行与该实例相关的一些操作。类方法是可以在不引用任何对象实例的情况下调用的方法;这些方法在其他语言中称为静态方法。由于不能在没有对象实例的情况下执行实例方法,因此实例方法仅在对象类中定义时才有用。相反,您可以在任何类型的类中定义类方法。

一、定义方法

1.1 定义类方法

若要将类方法添加到类中,请将如下所示的元素添加到类定义中:

ClassMethod MethodName(Arguments) as Classname [ Keywords]
{
//method implementation
}
  • MethodName 是方法的名称。
  • Arguments 是以逗号分隔的参数列表。
  • Classname 是一个可选的类名,表示此方法返回的值(如果有)的类型。如果方法不返回值,则省略 As Classname 部分。
    该类可以是数据类型类(DTC)、对象类或(不太常见的)无类型的类。类名可以是完整的类名,也可以是简短的类名。
  • Keywords 表示任何方法关键字。这些是可选的。请参阅本书前面的“编译器关键字”。
  • 方法的实现取决于方法的实现语言和类型。默认情况下,方法实现由零行或多行 Caché ObjectScript 组成。

1.2 定义实例方法

若要将实例方法添加到类中,请使用 Method 定义

Method MethodName(arguments) as Classname [ Keywords]
{
 //method implementation
}

二、指定方法参数

一个方法可以接受任意数量的参数。方法定义必须指定它所采用的参数。它还可以指定每个参数的类型默认值。(在此上下文中,type 是指任何类型的类,而不是特定的数据类型类。)

请考虑以下泛型类方法定义:

ClassMethod MethodName(Arguments) as Classname [ Keywords]
{
 //method implementation
}

这里 Arguments 具有以下一般形式:

argname1 as type1 = value1, argname2 as type2 = value2, argname3 as type3 = value3, [and so on]
  • argname1argname2argname3 等是参数的名称。 这些名称必须遵循变量名称的规则。
  • Type1Type2Type3 等是类名。方法定义的这一部分旨在向可能使用此方法的程序员描述要为相应参数传递的值类型。通常,显式指定每个方法参数的类型是一个好主意。
    通常,类型是数据类型类(DTC)或对象类。
    类名可以是完整的类名,也可以是简短的类名。
    您可以省略这部分语法。如果这样做,也省略 as 部分。
  • value1value2value3 等是参数的默认值。如果调用该方法时未为参数提供值,则该方法会自动将参数设置为等于此值。
    每个值可以是文本值(“abc”或 42),也可以是用大括号括起来的 Caché ObjectScript 表达式。例如:
ClassMethod Calculate(count As %Integer, name, state As %String = "CA",time As %Integer = {$horolog})
{
 // ...
}

三、传递参数

方法定义还向可能使用该方法的程序员指示每个参数的预期传递方式。参数可以按(默认技术)或引用传递。

通过引用传递特定论点可能是明智的,也可能是不明智的。详细信息取决于方法实现。因此,在定义方法时,应使用方法签名向其他程序员指示每个参数的使用方式。

若要指示应通过引用传递参数,请在方法签名中,在参数名称之前包含 ByRef 修饰符。下面显示了一个将 ByRef 用于其两个参数的示例:

/// Swap value of two integers
Method Swap(ByRef x As %Integer, ByRef y As %Integer)
{
    Set temp = x
    Set x = y
    Set y = temp
}

同样,若要指示参数应通过引用传递,并且不应具有传入值,请在方法签名中,在参数名称之前包含 Output 修饰符。例如:

Method CreateObject(Output newobj As MyApp.MyClass) As %Status
{
    Set newobj = ##class(MyApp.MyClass).%New()
    Quit $$$OK
}

四、可变数量的参数

您可以定义一个接受可变数量的参数的方法。为此,请在最后一个参数的名称后包含 ... ,如以下示例所示。此示例还演示了如何使用此功能。

ClassMethod MultiArg(Arg1... As %String)
{
 Write "Invocation has ",
     $GET(Arg1, 0),
     " element",
     $SELECT(($GET(Arg1, 0)=1):"", 1:"s"),
     !
 For i = 1 : 1 : $GET(Arg1, 0)
 {
     Write:($DATA(Arg1(i))>0) "Argument[", i , "]:", 
         ?15, $GET(Arg1(i), "<NULL>"), !
 }
 Quit
}

以下终端会话显示了此方法的行为方式:

SAMPLES>do ##class(VarNumArg.Demo).MultiArg("scooby","shaggy","velma","daphne","fred")
Invocation has 5 elements
Argument[1]:   scooby
Argument[2]:   shaggy
Argument[3]:   velma
Argument[4]:   daphne
Argument[5]:   fred

五、返回值

若要定义方法以使其返回值,请在该方法中使用以下任一方法(如果在 Caché ObjectScript 中实现该方法):

Return returnvalue
// 或者
Quit returnvalue

此方法返回一个对象实例:

ClassMethod FindPerson(id As %String) As Person
{
    Set person = ##class(Person).%OpenId(id)
    Return person
}

六、指定实现语言

在创建方法时,您可以选择实现语言。事实上,在单个类中,可以用不同的语言实现多个方法。无论实现语言如何,所有方法都可以互操作。

默认情况下,方法使用由其所属类的 Language 关键字指定的语言。对于此关键字,默认值为 cache(Caché ObjectScript)。其他选项包括 basic (Caché Basic)、java (Java)、javascript (JavaScript)、mvbasic (MVBasic) 和 tsql (TSQL)。

您可以通过为特定方法设置 Language 关键字来覆盖该方法的此值:

Class MyApp.Test {

/// A Basic method
Method TestB() As %Integer [ Language = basic]
{
    'This is Basic
    Print "This is a test"
    Return 1
}

/// A Cache ObjectScript method
Method TestC() As %Integer [ Language = cache]
{
    // This is Cache ObjectScript
    Write "This is a test"
    Quit 1
}
}

七、将方法投影为 SQL 存储过程

可以定义类方法(但不能定义实例方法),以便它也可以用作 SQL 存储过程。为此,请在方法定义中包含 SqlProc 关键字。

该过程的默认名称为 CLASSNAME_METHODNAME 若要指定其他名称,请指定 SqlName 关键字。

ClassMethod FindTotal(territory As %String) As %Integer [SqlProc]
{
    // use embedded sql to find total sales
    &sql(SELECT SUM(SalesAmount) INTO :total 
            FROM Sales
            WHERE Territory = :territory
    )

    Quit total
}

八、调用类方法

8.1 调用类方法

若要调用任何类的类方法(如果该方法不是私有的),请使用以下表达式:

##class(Package.Class).Method(Args)
  • 其中 Package.Class 是类的名称,Method 是方法的名称,Args 是方法的任何参数。
  • ##class 不区分大小写。

此表达式调用给定的类方法并获取其返回值(如果有)。您可以将此表达式与 DOSET 等命令一起使用,也可以将其用作其他表达式的一部分。:

do ##class(Package.Class).Method(Args)
set myval= ##class(Package.Class).Method(Args)
write ##class(Package.Class).Method(Args) 
set newval=##class(Package.Class).Method(Args)_##class(Package2.Class2).Method2(Args)

8.2 …语法

(在类方法中)若要调用该类的另一个类方法(可以是继承的方法),请使用以下表达式:

 do ..MethodName()
 set value=..MethodName(args)

不能在类方法中使用此语法来引用属性或实例方法,因为这些引用需要实例上下文

8.3 动态执行类方法

若要执行类方法,其中方法名称直到运行时才确定,请使用 $CLASSMETHOD 函数:

$CLASSMETHOD(classname, methodname, Arg1, Arg2, Arg3, ... )

其中 classname 的计算结果为类的完全限定名称,methodname 的计算结果为该类中类方法的名称,Arg1Arg2Arg3 等是该方法的任何参数。例如:

set cls="Sample.Person"
set clsmeth="PrintPersons" 
do $CLASSMETHOD(cls,clsmeth)

如果给定的方法不存在,或者它是实例方法,则系统将生成<METHOD DOES NOT EXIST> 错误。如果给定的方法为私有方法,则系统将生成 <PRIVATE METHOD> 错误。

8.4 将参数传递给方法

向方法传递参数的默认方法是按值传递。在此技术中,只需将参数作为变量、文本值或其他表达式包含在方法调用中。

也可以通过引用传递参数。其工作原理如下:系统有一个内存位置,其中包含每个局部变量的值。变量的名称充当内存位置的地址。将局部变量传递给方法时,将按值传递变量。这意味着系统会复制该值,因此原始值不受影响。您可以改为传递内存地址;这种技术称为通过引用调用。这也是将多维数组作为参数传递的唯一方法。
Caché ObjectScript 中,要通过引用传递参数,请在该参数前面加上句点。例如:

set MyArg(1)="value A"
set MyArg(2)="value B"
set status=##class(MyPackage.MyClass).MyMethod(.MyArg)

九、方法类型(CodeMode 选项)

Caché 支持四种类型的方法,类编译器以不同的方式处理这些方法:

  • 代码方法(最默认和最常见的方法)
  • 表达式方法
  • 调用方法
  • 方法生成器

9.1 Code 方法

代码方法是一种方法,其实现只是代码行。这是最典型的方法类型,也是默认设置。方法实现可以包含对实现语言有效的任何代码。

Method Double(val As %Integer) As %Integer [ CodeMode = code] 
{
  q val * 2
}

9.2 表达式方法

表达式方法是在某些情况下可以由类编译器替换的方法,使用指定表达式的直接内联替换。表达式方法通常用于需要快速执行速度的简单方法(例如在数据类型类中找到的方法)

Method Speak() As %String [CodeMode = expression]
{
    "Woof, Woof"
}

表达式方法的所有形式变量提供默认值是一个好主意。这样可以防止由于在运行时缺少实际变量而导致的潜在内联替换问题

Caché 不允许在表达式方法中使用或按引用调用参数。

9.3 调用方法

调用方法是一种特殊的机制,用于围绕现有 Caché 例程创建方法包装器。在将旧代码迁移到基于对象的应用程序时,这通常很有用。

将方法定义为调用方法表示每当调用该方法时都会调用指定的例程。调用方法的语法为:

Method Call() [ CodeMode = call ]
{
    Tag^Routine
}

其中 “Tag^Routine” 指定例程中的标记名称。

9.4 方法生成器

方法生成器实际上是类编译器在类编译过程中调用的一个小程序。其输出是该方法的实际运行时实现。方法生成器提供了一种继承方法的方法,这些方法可以生成根据继承类或属性的需要自定义的高性能专用代码。在 Caché 库中,数据类型和存储类广泛使用方法生成器。

Method MyMethod() [ CodeMode = objectgenerator ]
{
    Do %code.WriteLine(" Write """ _ %class.Name _ """")
    Do %code.WriteLine(" Quit")
    Quit $$$OK
}
  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值