簡體   English   中英

如何在SmallTalk(Pharo)中獲取郵件發件人?

[英]How do I get a message sender in SmallTalk (Pharo)?

我在使用SmallTalk時收到郵件的發件人時遇到問題。 我想要完成的是從另一個方法(B)修改方法(A)的返回值,該方法由第一個方法(A)調用。 再次...... A調用B,我希望B從A的上下文中返回一個值。

示例代碼:

這將是A:

A

| aResult aPartialResult |

aPartialResult := self B.

"do things with aPartialResult"

^aResult.

這將是B:

B

| aResult |

[ aResult := "do something" ]
                        on: Exception
                        do: ["make A return something"].
^aResult.

問題是我想要在B中提出的異常也可以在B中處理。 這就是為什么我不只是在B中引發一個例外來處理A中的一個例子而且很容易從那里返回。

我以為我可以使用thisContext做到這一點,但發件人是零。 同樣得到答案的原因也不會有什么害處......

提前致謝!

Guillermo,異常處理可以在這里無縫地替換一些不好的想法:

  1. 使用thisContext(這幾乎不是必需的,通常是一個壞主意)
  2. 傳遞字符串,例如'1 |',UserInterface invalidCartIdErrorMessage
  3. 使用return:使用這些字符串傳遞錯誤

另外,retrieveCart:onErrorReturnFrom:做得太多了。 使用所有錯誤處理程序,實際邏輯會丟失。

所以,我要做的第一件事是創建Error子類來表示你的域概念,例如AddBookError,CartExpiredError,InvalidCartError

然后你只需設置錯誤信息,也許像:

CartExpiredError>>initialize

    super initialize.
    self messageText: '1|', UserInterface cartHasExpiredErrorMessage.

接下來的事情(實際上是兩個步驟)是用私有訪問器替換原始字典方法,私有訪問器可以使用新的錯誤類,如下所示:

timestampFor: aCartId

    ^ cartCreationDateAndTime at: aCartId ifAbsent: [ InvalidCartError signal ].

cartNumber: aCartId 

     ^ carts at: aCartId ifAbsent: [ InvalidCartError signal ].

Cart>>add: aQuantity booksWithISBN: aBookISBN

    fail ifTrue: [ AddBookError signal ].

現在,retrieveCart:onErrorReturnFrom:可以變為:

retrieveCart: aCartId

    | aCartCreationDateAndTime |
    aCartCreationDateAndTime := self timestampFor: aCartId.
    Time now > (aCartCreationDateAndTime + 30 minutes) ifTrue:  [ CartExpiredError signal ].
    ^ self cartNumber: aCartId.

最后,大大簡化的A成為:

add: aQuantity booksWithISBN: aBookISBN toCart: aCartId

     | aCart |
    [aCart := self retrieveCart: aCartId.
    aCart add: aQuantity booksWithISBN: aBookISBN]
        on: Error
        do: [ :e |  ^ e messageText ].
    ^ '0|OK'.

這仍然可以被清理(例如,為preTending'1 |'添加到messageText的所有Error類創建一個超類),顯然你必須將這個簡化版本用於你的實際項目,但是你能開始看看例外如何讓你的生活更輕松?

是代碼的工作模型,在github上傳遞測試

nb我注意到的另一件事是aCartCreationDateAndTime。 將它作為購物車的屬性似乎更自然,但也許這在實際應用中沒有意義......

一個簡單的方法是A傳遞一個帶有返回B的塊,如:

A
   | aResult aPartialResult |
   aPartialResult := self BonSpecialConditionDo: [:partial | ^partial].
   ...snip...

然后

BonSpecialConditionDo: aBlock
    | partialResult |
    partialResult := self doSomethingPartial.
    ^[self doSomething]
        on: SomeException
        do: [:exc | aBlock value: partialResult]

注意,捕獲異常被認為是危險的(你捕獲了太多東西)。

編輯:我剛剛在處理程序中刪除了一個不必要的返回^

編輯:與超級大國一起做(但不要用錘子殺死蒼蠅)

B
    | partialResult |
    partialResult := self doSomethingPartial.
    ^[self doSomething]
        on: SomeException
        do: [:exc | thisContext home sender home return: partialResult ]

我以為你可以通過Exception exc訪問thisContext(這是實例變量handlerContext),但似乎沒有任何方便的消息來訪問這個內部狀態...

得到它了!

這是A:

A

| aResult aPartialResult |

aPartialResult := self BOnErrorReturnFrom: thisContext.

"do things with aPartialResult"

^aResult.

這將是B:

BOnErrorReturnFrom: aContext

| aResult |

[ aResult := "do something" ]
                        on: Exception
                        do: [aContext return: "whatever you want :)"].
^aResult.

在我意識到關鍵字“thisContext”在BlockClosure中使用后,並沒有返回聲明了塊的ContextPart而是返回其他內容(但仍然不確定它是什么)之后並沒那么難。

回應肖恩:

我試圖做的是避免重復代碼。 實現A和B的對象是REST接口的內部(模型側)部分,所以我希望它返回一個字符串,只返回一個字符串(我不想要異常,也不需要任何不同於字符串對象的東西) 。 在我的具體問題中,A(很抱歉打破了Smalltalk消息命名約定,但我認為現在更改它會導致進一步的混淆......)會收到購物車ID並會對該購物車執行某些操作。 A必須使用該ID檢索購物車,在購物車上進行一些驗證,如果有錯誤,則返回ad hoc消息(始終作為字符串)。 將在每個必須檢索購物車的消息中重復此檢索和驗證代碼。

這是我最終獲得的正確代碼:

這是A :(不要注意#try消息。它只是確保沒有異常會被轉換為字符串。如果有人知道如何以更好的方式做到這一點,請告訴我如何!)

add: aQuantity booksWithISBN: aBookISBN toCart: aCartId

    | aCart aContext |

    aContext := thisContext.

    ^self try: [

        aCart := self retrieveCart: aCartId onErrorReturnFrom: aContext.

        [aCart add: aQuantity booksWithISBN: aBookISBN]
                                                    on: Error
                                                    do: [ :anError | ^'1|', (self formatAsResponse: anError messageText) ].

        ^'0|OK'.
    ].

這是B:

retrieveCart: aCartId onErrorReturnFrom: aContext

    | aCartCreationDateAndTime aCart |

    [aCartCreationDateAndTime := cartCreationDateAndTime at: aCartId asInteger.]
                                                                                    on: KeyNotFound 
                                                                                    do: [ aContext return: ('1|', (UserInterface invalidCartIdErrorMessage)).].

    (systemClock now > (aCartCreationDateAndTime + 30 minutes)) 
                                                            ifTrue:  [aContext return: ('1|', (UserInterface cartHasExpiredErrorMessage))].

    [aCart := carts at: aCartId asInteger.]
                                    on: KeyNotFound
                                    do: [ aContext return: ('1|', (UserInterface invalidCartIdErrorMessage))].

    ^aCart.

一種

| aResult aPartialResult |

aPartialResult:= self B.

“用aPartialResult做事”

^ aResult。

| aResult |

[aResult:=“做某事”]:例外:[“讓A返回一些東西”]。 ^ aResult。

我會把它寫成

一種

| aResult aPartialResult |

aPartialResult:= self B. aPartialResult ifNotNil:[

“用aPartialResult做事”。

^ aResult。

| aResult |

[aResult:=“做某事”]:例外:[:e | ^ nil]。 ^ aResult。

那么那就是我!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM