第五章 Caché 定義和調用方法

第五章 定義和調用方法

方法介紹

方法是由類定義的可執(zhí)行元素。Caché 支持兩種類型的方法:實例方法和類方法铜靶。從類的特定實例調用實例方法僚匆,并通常執(zhí)行與該實例相關的一些操作。類方法是無需引用任何對象實例即可調用的方法;這些在其他語言中稱為靜態(tài)方法黄虱。

方法通常指的是實例方法稚矿。更具體的類方法用于引用類方法。

因為沒有對象的實例就不能執(zhí)行實例方法捻浦,所以實例方法只有在對象類中定義時才有用晤揣。相反,可以在任何類中定義類方法朱灿。

定義方法

要將類方法添加到類中昧识,請在類定義中添加如下元素:

ClassMethod MethodName(Arguments) as Classname [ Keywords]
{
//method implementation
}
  • MethodName 是方法的名稱,最長180個字符。
  • Arguments 參數以逗號分割盗扒。
  • Classname 是一個可選的類名跪楞,表示此方法返回的值的類型。如果方法不返回值侣灶,則省略As Classname部分甸祭。

類可以是數據類型類、對象類褥影,或者(不太常見的)無類型類池户。類名可以是完整的類名,也可以是簡短的類名。(如果用IMPORT 關鍵字可以使用簡稱)

  • Keywords 代表關鍵字
  • 方法的實現取決于實現語言和方法的類型;

要將實例方法添加到類中校焦,請使用與方法相同的語法赊抖,而不是使用ClassMethod:

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

實例方法只與對象類相關。

指定方法參數:基礎

方法可以接受任意數量的參數寨典。方法定義必須指定它所接受的參數氛雪。還可以為每個參數指定類型和默認值。(在這個上下文中耸成,type指的是任何類型的類报亩,而不是特定的數據類型類。)

通用類方法定義:

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

這里參數可以有以下形式

argname1 as type1 = value1, argname2 as type2 = value2, argname3 as type3 = value3, [and so on]
  • argname1, argname2, argname3, and so on 是參數名墓猎,這些名稱必須遵循變量名稱的規(guī)則捆昏。
  • type1, type2, type3, and so on 是類名 方法定義的這一部分旨在向可能使用此方法的程序員描述要傳遞什么類型的值作為相應的參數。通常毙沾,顯式地指定每個方法參數的類型是一個好習慣骗卜。

通常,類型是數據類型類或對象類左胞。

類名可以是完整的類名寇仓,也可以是簡短的類名。(IMPORT關鍵字導入類可使用簡名)

可以忽略這部分語法烤宙。如果你這樣做了遍烦,也可以省略as部分。

  • value1, value2, value3, and so on 是參數值躺枕,如果在沒有為參數提供值的情況下調用方法服猪,則該方法將自動將參數設置為該值。

每個值可以是一個字符串(“abc”或42)拐云,也可以是一個用大括號括起來的Caché ObjectScript表達式罢猪。例如:

ClassMethod Test(flag As %Integer = 0)
{
 //method implementation
}

ClassMethod Test(time As %Integer = {$horolog} )
{
 //method implementation
}

可以忽略這部分語法。如果這樣做了叉瘩,也可以省略等號(=)膳帕。

例如,下面是一個帶有三個參數的Calculate()方法:

ClassMethod Calculate(count As %Integer, name, state As %String = "CA")
{
 // ...
}

其中count和state分別聲明為%Integer和%String薇缅。默認情況下危彩,參數是%String數據類型,因此未指定類型的參數是%String泳桦。以上示例中的name就是這種情況汤徽。

如何傳遞參數

方法定義還表明,對于可能使用該方法的程序員灸撰,如何傳遞每個參數谒府。參數可以通過值或引用傳遞(ref)

通過引用傳遞特定的參數可能明智漆羔,也可能不明智。細節(jié)取決于方法實現狱掂。因此,在定義方法時亲轨,應該使用方法簽名向其他程序員表明如何使用每個參數趋惨。

要指示應通過引用傳遞參數,請在方法簽名中參數名稱之前包含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

注意:$GET(Arg1, 0) 如果為空库正,第二個參數是代表默認值

返回值

要定義一個方法以便它返回一個值,請在該方法中使用下列任一項(如果在Caché ObjectScript中實現該方法):

 Return returnvalue

 Quit returnvalue

其中returnvalue是方法返回的合適值厘唾。這應該與方法聲明的返回類型一致褥符。如果返回類型是數據類型類,則該方法應該返回一個文字值抚垃。如果返回類型是一個對象類喷楣,那么該方法應該返回該類的一個實例(特別是OREF)。

例如

ClassMethod Square(input As %Numeric) As %Numeric
{
    Set returnvalue = input * input
    Return returnvalue
}

返回對象

/// w ##class(PHA.OP.MOB.Test).FindPerson(2)
ClassMethod FindPerson(id As %String) As PHA.OP.MOB.Android
{
    Set person = ##class(User.DHCPHARWIN).%OpenId(id)
    Return person
}
DHC-APP>w ##class(PHA.OP.MOB.Test).FindPerson(2)
DHC-APP 2e1>w person
1@User.DHCPHARWIN
DHC-APP 2e1>zw person
person=<OBJECT REFERENCE>[1@User.DHCPHARWIN]
+----------------- general information ---------------
|      oref value: 1
|      class name: User.DHCPHARWIN
|           %%OID: $lb("2","User.DHCPHARWIN")
| reference count: 2
+----------------- attribute values ------------------
|       %Concurrency = 1  <Set>
|   PHAAutoPrintDate = ""
|     PHAAutoPrintIP = ""
|   PHAAutoPrintTime = ""
|       PHAChkStatus = ""
|         PHAChkUser = ""
|     PHAChkUserCode = ""
|      PHAConfigUser = ""
|  PHAConfigUserCode = ""
|            PHADATE = 65261
|        PHADeviceID = ""
|          PHAEMFLAG = ""
|         PHAFINDATE = 64730
|         PHAFINFLAG = ""
|        PHALastDate = 65261
|        PHALastTime = 37684
|         PHALocCode = ""
|          PHANOUSER = ""
|       PHAPRINTDATE = 65259
|       PHAPRINTFLAG = ""
|       PHAPRINTTIME = 37686
|           PHAPRTDR = 223382
|     PHAPresChkDate = ""
|     PHAPresChkTime = ""
|       PHAPriorFlag = "N"
|         PHARETFLAG = 1
|     PHAStartPyFlag = 10
|          PHAStatus = 10
|            PHATIME = 53860
|         PHAWinDesc = ""
|            PHAZFCL = ""
|         PhaPrescNo = "O180323000005"
|      PhaUndsipFlag = ""
|     phalcdserialno = 0
+----------------- swizzled references ---------------
|       i%PHAPAPMIDR = 81
|       r%PHAPAPMIDR = ""
|         i%PHAPHLDR = 11
|         r%PHAPHLDR = ""
|         i%PHAPHWDR = 42
|         r%PHAPHWDR = ""
|   i%PHAPRINTUSERDR = ""
|   r%PHAPRINTUSERDR = ""
|       i%PHAQueueNo = ""
|       r%PHAQueueNo = ""
|        i%Phaphpydr = ""
|        r%Phaphpydr = ""
+-----------------------------------------------------

注意:Return與Quit用法相同

實現語言

在創(chuàng)建方法時鹤树,可以選擇實現語言铣焊。實際上,在一個類中魂迄,可以用不同的語言實現多個方法粗截。所有方法互操作,而不考慮實現語言捣炬。

默認情況下熊昌,方法使用其所屬類的language關鍵字指定的語言。對于這個關鍵字湿酸,默認是Caché (Caché ObjectScript)婿屹。其他選項有basic (Cache basic)、java (java)推溃、javascript (javascript)昂利、mvbasic (mvbasic)和tsql (tsql)。

注意:Caché ObjectScript Caché腳本 即M語言

可以通過為特定的方法設置語言關鍵字來覆蓋它:

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 = Caché]
    {
        // This is Cache ObjectScript
        Write "This is a test"
        Quit 1
    }
}

方法的類型(CodeMode選項)

Caché 支持四種類型的方法,類編譯器處理不同:

代碼方法 Code Methods

代碼方法的實現只是幾行代碼蜂奸。這是最典型的方法類型犁苏,也是默認的。

方法實現可以包含對實現語言有效的任何代碼扩所。

注意:Caché提供了一組系統定義的方法來執(zhí)行簡單围详、常見的任務。如果用戶定義的方法執(zhí)行這些任務之一祖屏,則編譯器不會為其生成任何可執(zhí)行代碼助赞。相反,它將用戶定義的方法與系統定義的方法關聯起來袁勺,因此調用用戶定義的方法將導致對系統定義的方法的調用雹食,從而帶來相關的性能好處。而且期丰,調試器不會單步執(zhí)行這樣一個系統定義的方法群叶。

表達方法 Expression Methods

表達式方法是一種方法,在某些情況下咐汞,類編譯器可以使用指定表達式的直接內聯替換來替換它盖呼。表達式方法通常用于需要快速執(zhí)行速度的簡單方法(如數據類型類中的方法)。

例如化撕,可以將Dog類的Speak()方法從前面的示例轉換為表達式方法:

/// w ##class(PHA.OP.MOB.Test).Speak()
ClassMethod Speak() As %String [ CodeMode = expression ]
{
"Woof, Woof"
}
DHC-APP>w ##class(PHA.OP.MOB.Test).Speak()
Woof, Woof

假設dog是指dog對象几晤,則該方法可采用如下方法:

Write dog.Speak()

這可能導致生成以下代碼:

Write "Woof, Woof"

為表達式方法的所有形式變量提供默認值是一個好主意。這可以防止由于運行時缺少實際變量而導致的潛在內聯替換問題植阴。
注意:Caché不允許在表達式方法中使用宏或引用調用參數蟹瘾。

調用方法 Call Methods

調用方法是在現有Caché 程序周圍創(chuàng)建方法包裝器的一種特殊機制。在將遺留代碼遷移到基于對象的應用程序時掠手,這通常很有用憾朴。

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

其中“Tag^例程”指定了程序例程中的一個標簽名。

注意:CodeMode = call沒有這個關鍵字 程序報錯

Call()
 s dog="小狗"
 w dog,!
 q dog
/// w ##class(PHA.OP.MOB.Test).Call()
ClassMethod Call() [ CodeMode = call ]
{
Call^PHA.MOB.TEST

}

DHC-APP>w ##class(PHA.OP.MOB.Test).Call()
小狗

注意:routine是宏程序 Tag^Routine

方法生成器 Method Generators

方法生成器實際上是一個由類編譯器在類編譯期間調用的小程序喷鸽。它的輸出是該方法的實際運行時實現众雷。方法生成器提供了一種繼承方法的方法,可以生成高性能的專門代碼做祝,這些代碼根據繼承類或屬性的需要進行定制砾省。在Caché庫中,數據類型和存儲類廣泛使用方法生成器混槐。

/// d ##class(PHA.OP.MOB.Test).MyMethod()
/// PHA.OP.MOB.Test
ClassMethod MyMethod() [ CodeMode = objectgenerator ]
{
        Do %code.WriteLine(" Write """ _ %class.Name _ """")
        Do %code.WriteLine(" Quit")
        Quit $$$OK
}

DHC-APP 2d1> d ##class(PHA.OP.MOB.Test).MyMethod()
PHA.OP.MOB.Test

注意:必須有objectgenerator關鍵字 才可以用%class编兄,%code 關鍵字

將方法映射為SQL存儲過程

可以定義一個類方法(但不是實例方法),以便它也可以作為SQL存儲過程使用声登。為此狠鸳,在方法定義中包含SqlProc關鍵字揣苏。

該過程的默認名稱為CLASSNAME_METHODNAME。要指定一個不同的名稱件舵,請指定SqlName關鍵字卸察。

調用類方法

本節(jié)討論如何在Caché ObjectScript中調用類方法。本節(jié)適用于所有的類铅祸。注意蛾派,下一章將討論實例方法,因為它們只適用于對象類个少。

  • 要調用任何類的類方法(如果該方法不是私有的),請使用以下表達式:
##class(Package.Class).Method(Args)
  • Package.Class 是類名
  • Method 方法名
  • Args 方法的參數
  • class 不區(qū)分大小寫

這個表達式調用給定的類方法并獲得它的返回值(如果有的話)眯杏∫菇梗可以將此表達式與DO和SET等命令一起使用,也可以將其用作另一個表達式的一部分茫经。以下是一些變化:

 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)    

可以忽略這個包。如果這樣做萎津,類編譯器將確定要使用的正確包名 (IMPORT)

  • (在一個類方法中)調用該類的另一個類方法(可以是一個繼承的方法)卸伞,使用以下表達式:
..MethodName(args)

可以使用DO命令來使用這個表達式。如果方法返回一個值锉屈,可以使用SET荤傲,或者將其用作另一個表達式的一部分。以下是一些變化:

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

注意:不能在類方法中使用此語法來引用屬性或實例方法颈渊,因為這些引用需要實例上下文遂黍。

  • 要執(zhí)行一個類方法,其中的方法名直到運行時才確定俊嗽,使用$CLASSMETHOD函數:
$CLASSMETHOD(classname, methodname, Arg1, Arg2, Arg3, ... )
  • classname 計算為類的全名雾家。
  • methodname 計算結果為該類中的類方法的名稱,
  • Arg1, Arg2, Arg3 方法參數
/// d ##class(PHA.OP.MOB.Test).CLASSMETHODTEST()
/// 輸出 Woof, Woof
ClassMethod CLASSMETHODTEST()
{
    set cls="PHA.OP.MOB.Test"
    set clsmeth="Speak" 
    S RET= $CLASSMETHOD(cls,clsmeth)
    q RET
}

如果給定的方法不存在绍豁,或者它是一個實例方法芯咧,Caché生成的<方法不存在><METHOD DOES NOT EXIST>錯誤。如果給定的方法是私有的竹揍,緩存將生成<私有方法> <PRIVATE METHOD>錯誤敬飒。

  • PRIVATE 方法 ##super可以調用 其他類則報錯
DHC-APP>w ##class(PHA.OP.MOB.API).Login("demo#1")
{"retVal":"success","retObject":{"userCode":"demo","userName":"Demo Group","userID":1,"rows":[{"locID":"312","locDesc":"煎藥室","groupID":"176","groupDesc":"煎     藥室"}]}}
DHC-APP>w ##class(PHA.OP.MOB.Business).Login("yf01#1")
 
W ##CLASS(PHA.OP.MOB.Business).Login("yf01#1")
^
<PRIVATE METHOD>

將參數傳遞給方法

將參數傳遞給方法的默認方式是按值傳遞。在這種技術中鬼佣,只需將參數作為變量驶拱、文字值或其他表達式包含在方法調用中,如前面的示例所示晶衷。

也可以通過引用傳遞參數蓝纲。

它的工作原理如下:系統有一個包含每個局部變量值的內存位置阴孟。變量的名稱充當內存位置的地址。將局部變量傳遞給方法時税迷,將通過值傳遞變量永丝。這意味著系統復制了該值,因此原始值不會受到影響箭养。你可以傳遞內存地址;這種技術稱為引用調用慕嚷。它也是傳遞多維數組作為參數的唯一方法。
在Caché ObjectScript中毕泌,若要通過引用傳遞參數喝检,請在該參數之前加上"."。例如:

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

在本例中,通過引用傳遞一個值(一個多維數組)撼泛,以便該方法可以接收該值挠说。在其他情況下,通過引用傳遞參數是很有用的愿题,這樣就可以在運行方法之后使用它的值损俭。例如:

 set status=##class(MyPackage.MyClass).GetList(.list)
 //use the list variable in subsequent logic

在其他情況下,可以為變量指定一個值潘酗,調用修改它的方法(并通過引用返回它)杆兵,然后使用更改后的值。

/// d ##class(PHA.OP.MOB.Test).TestPassingArguments()
ClassMethod TestPassingArguments()
{
    set MyArg(1)="value A"
    set MyArg(2)="value B"
    S RET=..TestPassingArguments1(.MyArg)
    zw MyArg
    q RET
}

ClassMethod TestPassingArguments1(ByRef MyArg)
{
    set MyArg(3)="value C"
    set MyArg(4)="value D"
    b
    q "TestPassingArguments1"
}
DHC-APP>d ##class(PHA.OP.MOB.Test).TestPassingArguments()
 
  b
  ^
<BREAK>zTestPassingArguments1+3^PHA.OP.MOB.Test.1
DHC-APP 3e1>zw MyArg
MyArg(1)="value A"
MyArg(2)="value B"
MyArg(3)="value C"
MyArg(4)="value D"
 
DHC-APP 3e1>g
MyArg(1)="value A"
MyArg(2)="value B"
MyArg(3)="value C"
MyArg(4)="value D"
 
DHC-APP>

鑄造方法

要將一個類的方法轉換為另一個類的方法仔夺,語法如下(在cache ObjectScript中):

Do ##class(Package.Class1)Class2Instance.Method(Args)
Set localname = ##class(Package.Class1)Class2Instance.Method(Args)

可以同時轉換類方法和實例方法琐脏。
例如,假設有兩個類缸兔,MyClass.Up和MyClass.Down,骆膝,兩個都有Go()方法。

MyClass.Up灶体,這個方法如下

Method Go()
{
    Write "Go up.",!
}

MyClass.Down,阅签,這個方法如下

Method Go()
{
    Write "Go down.",!
}

然后可以創(chuàng)建MyClass.Up的一個實例。并使用它來調用MyClass.Down蝎抽。方法:

>Set LocalInstance = ##class(MyClass.Up).%New()
 
>Do ##class(MyClass.Down)LocalInstance.Go()
Go down.

在表達式中使用##類也是有效的

Write ##class(Class).Method(args)*2

沒有設置一個等于返回值的變量政钟。

更通用的方法是使用method和CLASSMETHOD函數,它們分別是實例方法和類方法樟结。這些在本章前面的章節(jié)中有描述养交。

Class PHA.OP.MOB.TestTwo Extends PHA.OP.MOB.Test
{

Method Go()
{
    Write "Go down.",!
}

}

Class PHA.OP.MOB.Test Extends %RegisteredObject
{
Method Go()
{
    Write "Go up.",!
}

/// d ##class(PHA.OP.MOB.Test).CastingMethod()
ClassMethod CastingMethod()
{
    Set LocalInstance = ##class(PHA.OP.MOB.TestTwo).%New()
 
    Do ##class(PHA.OP.MOB.Test)LocalInstance.Go()
}
}

DHC-APP>d ##class(PHA.OP.MOB.TestThree).CastingMethod()
 
 Do ##class(PHA.OP.MOB.Test)LocalInstance.Go()
 ^
<INVALID CLASS>zCastingMethod+2^PHA.OP.MOB.TestThree.1 *super-class 'PHA.OP.MOB.Test' is not in sub-class 'PHA.OP.MOB.TestTwo' hierarchy
DHC-APP 2d1>k
 
DHC-APP 2d1>q
 
DHC-APP>d ##cla

注意必須是主子關系的類!

重寫繼承的方法

類從父類或父類繼承方法(類和實例方法)瓢宦。除了標記為Final的方法外碎连,可以通過在該類中提供定義來覆蓋這些定義。

/// d ##class(PHA.OP.MOB.Test).CLASSMETHODTEST()
/// 輸出 Woof, Woof
ClassMethod CLASSMETHODTEST() [ Final ]
{
    set cls="PHA.OP.MOB.Test"
    set clsmeth="Speak" 
    S RET= $CLASSMETHOD(cls,clsmeth)
    q RET
}

子類重寫父類FINAL方法時會報錯

Studio
---------------------------
錯誤 #5272: 無法更改最終'Method': 'CLASSMETHODTEST'

  > 錯誤 #5030: 在編譯類PHA.OP.MOB.TestTwo時出錯
---------------------------
確定   
---------------------------

如果這樣做驮履,請注意以下規(guī)則:

  • 如果方法是父類中的類方法鱼辙,則不能將其作為子類中的實例方法覆蓋廉嚼,反之亦然。
  • 子類方法的返回類型必須與原始返回類型或原始返回類型的子類相同倒戏。
  • 子類中的方法可以比父類中的方法有更多的參數怠噪。
  • 子類中的方法可以為參數指定不同的默認值。
  • 子類方法中的參數類型必須與原始方法中的參數類型一致杜跷。具體地說傍念,任何給定的參數必須與原始類型或原始類型的子類相同。

注意葛闷,如果一個參數沒有指定類型憋槐,編譯器會將該參數視為%String。因此淑趾,如果超類方法中的參數沒有類型秦陋,則子類方法的相應參數可以是%String,可以是%String的子類治笨,也可以沒有類型。

  • 子類中的方法應該以與父類中的方法相同的方式接收參數值赤嚼。例如旷赖,如果給定的參數是通過引用在父類中傳遞的,那么同樣的參數應該通過引用在子類中傳遞更卒。

如果方法簽名在這方面不一致等孵,其他開發(fā)人員就很難知道如何正確使用方法。但是蹂空,請注意俯萌,編譯器不會發(fā)出錯誤。

如果的方法實現需要調用與父類中定義的同名方法上枕,可以使用語法##super()咐熙,這將在小節(jié)中討論。

##super()關鍵字

在一個方法中辨萍,使用下面的表達式來調用在最近的父類中定義的同名方法:

##super()

可以用DO命令來使用這個表達式棋恼。如果方法返回一個值,可以使用SET锈玉,或者將其用作另一個表達式的一部分爪飘。以下是一些變化:

 do ##super()
 set returnvalue=##super()_"additional string"

注意:##super不區(qū)分大小寫。還要注意拉背,與本章中的其他特性不同师崎,##super()可以在Basic 本方法中使用,也可以在ObjectScript方法中使用椅棺。

如果定義了一個方法犁罩,該方法應該調用超類的現有方法齐蔽,然后執(zhí)行一些附加的步驟,例如修改它的返回值昼汗,那么這是非常有用的肴熏。

##super 和 方法參數

super也適用于接受參數的方法。如果子類方法沒有為參數指定默認值顷窒,請確保該方法通過引用父類傳遞參數蛙吏。

例如,假設父類(MyClass.Up.SelfAdd())中的方法的代碼是:

ClassMethod SelfAdd(Arg As %Integer)
{
    Write Arg,!
    Write Arg + Arg
}

則其輸出為:

>Do ##Class(MyClass.Up).SelfAdd(2)
2
4
>

子類中的方法(MyClass.Down.SelfAdd())使用##super并通過引用傳遞參數:

ClassMethod SelfAdd(Arg1 As %Integer)
{
    Do ##super(.Arg1)
    Write !
    Write Arg1 + Arg1 + Arg1
}

則其輸出為:

>Do ##Class(MyClass.Down).SelfAdd(2)
2
4
6
>

在MyClass.Down.SelfAdd()中鞋吉,注意參數名前面的句點"."鸦做。如果我們忽略".",并且在不提供參數的情況下調用方法谓着,我們將收到一個 <UNDEFINED> error泼诱。

DHC-APP> d ##class(PHA.OP.MOB.TestTwo).SelfAdd(3)
 
    Write Arg,!
    ^
<UNDEFINED>zSelfAdd+1^PHA.OP.MOB.Test.1 *Arg

注意 父類如果有參數,必須指定參數 否則報錯赊锚。

調用 ##super 的影響

super只影響當前方法調用治筒。如果該方法進行任何其他調用,則這些調用相對于當前對象或類舷蒲,而不是父類耸袜。

例如,假設MyClass.Up有MyName()和CallMyName()方法:

Class MyClass.Up Extends %Persistent
{

ClassMethod CallMyName()
{
    Do ..MyName()
}

ClassMethod MyName()
{
    Write "Called from MyClass.Up",!
}

}

MyClass.Down 重寫這些方法如下:

Class MyClass.Down Extends MyClass.Up
{

ClassMethod CallMyName()
{
    Do ##super()
}

ClassMethod MyName()
{
    Write "Called from MyClass.Down",!
}

}

然后調用CallMyName()方法會得到以下結果:

USER>d ##class(MyClass.Up).CallMyName()
Called from MyClass.Up
 
USER>d ##class(MyClass.Down).CallMyName()
Called from MyClass.Down

MyClass.Down.CallMyName() 和MyClass.Up.CallMyName() 輸入不同是因為牲平,因為它的CallMyName()方法包含了##super堤框,所以調用了MyClass.Up.CallMyName()方法,然后調用未強制轉換的MyClass.Down.MyName()方法纵柿。

參數個數

在某些情況下蜈抓,可能會發(fā)現有必要向父類中的方法添加新參數,從而產生比子類中的方法中定義的參數更多的參數昂儒。子類仍然會進行編譯沟使,因為(為了方便起見)編譯器會將添加的參數附加到子類中的方法中。在大多數情況下渊跋,仍然應該檢查擴展該方法的所有子類格带,編輯簽名以說明附加的參數,并決定是否也要編輯代碼刹枉。即使你不想編輯簽名或代碼叽唱,你仍然必須考慮兩點:

  • 確保添加的參數名稱與子類中方法中使用的任何變量的名稱不相同。編譯器將添加的參數附加到子類中的方法微宝。如果這些參數碰巧與子類方法中使用的變量具有相同的名稱棺亭,就會出現意外的結果。
  • 如果子類中的方法使用了添加的參數(因為這個方法使用了##super)蟋软,確保父類中的方法為添加的參數指定默認值镶摘。
ClassMethod SelfAdd(Arg As %Integer, ARG2 As %Integer = 2)
{
    Write Arg,!
    Write Arg + Arg+ARG2
}

/// d ##class(PHA.OP.MOB.TestTwo).SelfAdd(1)
ClassMethod SelfAdd(Arg1 As %Integer)
{
    Do ##super(Arg1)
    Write !
    b
    Write Arg1 + Arg1 + Arg1
}

注意:父類如果有修改參數嗽桩,一定要添加默認值

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市凄敢,隨后出現的幾起案子碌冶,更是在濱河造成了極大的恐慌,老刑警劉巖涝缝,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扑庞,死亡現場離奇詭異,居然都是意外死亡拒逮,警方通過查閱死者的電腦和手機罐氨,發(fā)現死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滩援,“玉大人栅隐,你說我怎么就攤上這事⊥婊玻” “怎么了租悄?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長恩袱。 經常有香客問我泣棋,道長,這世上最難降的妖魔是什么憎蛤? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮纪吮,結果婚禮上俩檬,老公的妹妹穿的比我還像新娘。我一直安慰自己碾盟,他們只是感情好棚辽,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著冰肴,像睡著了一般屈藐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上熙尉,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天联逻,我揣著相機與錄音,去河邊找鬼检痰。 笑死包归,一個胖子當著我的面吹牛,可吹牛的內容都是我干的铅歼。 我是一名探鬼主播公壤,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼换可,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了厦幅?” 一聲冷哼從身側響起沾鳄,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎确憨,沒想到半個月后译荞,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡缚态,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年磁椒,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玫芦。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡浆熔,死狀恐怖,靈堂內的尸體忽然破棺而出桥帆,到底是詐尸還是另有隱情医增,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布老虫,位于F島的核電站叶骨,受9級特大地震影響,放射性物質發(fā)生泄漏祈匙。R本人自食惡果不足惜忽刽,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望夺欲。 院中可真熱鬧跪帝,春花似錦、人聲如沸些阅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽市埋。三九已至黎泣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缤谎,已是汗流浹背抒倚。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坷澡,地道東北人衡便。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親镣陕。 傳聞我的和親對象是個殘疾皇子谴餐,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內容