繁体   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